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
data/grammar/test.nml CHANGED
@@ -1,10 +1,12 @@
1
- [template]
2
- vblock {
3
- ...styleSpread
4
- }
5
-
6
1
  [style]
7
- styleSpread {
8
- background: rgb(86, 116, 25);
9
- outline_color: rgba(191, 112, 112, 0.67);
2
+ mainContainer {
3
+ int: 38;
4
+ bool: true;
5
+ float: 0.3;
6
+ string: "foobar";
7
+ func: outline(0, 0, 1, 0);
8
+ }
9
+
10
+ other {
11
+ bool: false;
10
12
  }
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.1.3'
3
+ s.version = '0.1.4'
4
4
  s.licenses = ['PPL']
5
5
  s.summary = "A Ruby library for writing GUI applications"
6
6
  s.authors = ["skinnyjames"]
@@ -19,4 +19,5 @@ Gem::Specification.new do |s|
19
19
  s.add_dependency "concurrent-ruby", "~> 1.3.4"
20
20
  s.add_dependency "raylib-bindings", "~> 0.7.9"
21
21
  s.add_dependency "sdl2-bindings", "~> 0.2.3"
22
+ s.add_dependency "memory_profiler"
22
23
  end
Binary file
Binary file
data/ui/examples/buddy.rb CHANGED
@@ -2,26 +2,28 @@ require_relative "../src/hokusai"
2
2
  require_relative "../src/hokusai/backends/sdl2"
3
3
  require_relative "../src/hokusai/backends/raylib"
4
4
 
5
- module Buddy
6
- class App < Hokusai::Block
7
- template <<~EOF
8
- [template]
9
- buddy {
10
- width="400"
11
- height="400"
12
- :source="buddy_img"
13
- }
14
- EOF
5
+ module Demos
6
+ module Buddy
7
+ class App < Hokusai::Block
8
+ template <<~EOF
9
+ [template]
10
+ buddy {
11
+ width="400"
12
+ height="400"
13
+ :source="buddy_img"
14
+ }
15
+ EOF
15
16
 
16
- uses(buddy: Hokusai::Blocks::Image)
17
+ uses(buddy: Hokusai::Blocks::Image)
17
18
 
18
- def buddy_img
19
- "#{__dir__}/assets/science-troll.png"
19
+ def buddy_img
20
+ "#{__dir__}/assets/science-troll.png"
21
+ end
20
22
  end
21
23
  end
22
24
  end
23
25
 
24
- Hokusai::Backends::RaylibBackend.run(Buddy::App) do |config|
26
+ Hokusai::Backends::RaylibBackend.run(Demos::Buddy::App) do |config|
25
27
  config.width = 500
26
28
  config.height = 500
27
29
  config.title = "Buddy"
data/ui/examples/clock.rb CHANGED
@@ -5,45 +5,47 @@ require_relative "./tic_tac_toe"
5
5
  require_relative "./counter"
6
6
  require "date"
7
7
 
8
- class Clock < Hokusai::Block
9
- template <<~EOF
10
- [template]
11
- vblock { background="22,22,22" height="50"}
12
- label { :content="time" size="30" color="233,233,233" }
13
- hblock
14
- game { @width="set_width"}
15
- [if="fullscreen"]
16
- stock
17
- EOF
18
-
19
- uses(
20
- vblock: Hokusai::Blocks::Vblock,
21
- hblock: Hokusai::Blocks::Hblock,
22
- empty: Hokusai::Blocks::Empty,
23
- label: Hokusai::Blocks::Label,
24
- game: TicTacToe::App,
25
- stock: Counter
26
- )
27
-
28
- attr_accessor :width
29
-
30
- provide :clock_time, :time
31
-
32
- def time
33
- time = DateTime.now
34
- "#{time.hour}:#{time.minute} #{time.second}"
35
- end
36
-
37
- def set_width(width)
38
- @width = width
39
- end
40
-
41
- def fullscreen
42
- (width || 0) > 500
8
+ module Demos
9
+ class Clock < Hokusai::Block
10
+ template <<~EOF
11
+ [template]
12
+ vblock { background="22,22,22" height="50"}
13
+ label { :content="time" size="30" color="233,233,233" }
14
+ hblock
15
+ game { @width="set_width"}
16
+ [if="fullscreen"]
17
+ stock
18
+ EOF
19
+
20
+ uses(
21
+ vblock: Hokusai::Blocks::Vblock,
22
+ hblock: Hokusai::Blocks::Hblock,
23
+ empty: Hokusai::Blocks::Empty,
24
+ label: Hokusai::Blocks::Label,
25
+ game: TicTacToe::App,
26
+ stock: Counter
27
+ )
28
+
29
+ attr_accessor :width
30
+
31
+ provide :clock_time, :time
32
+
33
+ def time
34
+ time = DateTime.now
35
+ "#{time.hour}:#{time.minute} #{time.second}"
36
+ end
37
+
38
+ def set_width(width)
39
+ @width = width
40
+ end
41
+
42
+ def fullscreen
43
+ (width || 0) > 500
44
+ end
43
45
  end
44
46
  end
45
47
 
46
- Hokusai::Backends::SDLBackend.run(Clock) do |config|
48
+ Hokusai::Backends::SDLBackend.run(Demos::Clock) do |config|
47
49
  config.after_load do
48
50
  # Note: how to load a font...
49
51
  # Thank you to Vladimir Nikolic - https://www.1001fonts.com/users/vladimirnikolic/
@@ -1,108 +1,110 @@
1
1
  require_relative "../src/hokusai"
2
2
  require_relative "../src/hokusai/backends/raylib"
3
3
 
4
- class Counter < Hokusai::Block
5
- style <<~EOF
6
- [style]
7
- additionStyles {
8
- background: rgb(214, 49, 24);
9
- rounding: 0.0;
10
- outline: outline(1,4,4,1);
11
- outline_color: rgb(216, 26, 137);
12
- }
13
-
14
- additionLabel {
15
- size: 40;
16
- color: rgb(255,255,255);
17
- }
18
-
19
- subtractStyles {
20
- background: rgb(0, 85, 170);
21
- rounding: 0.0;
22
- }
23
-
24
- subtractLabel {
25
- size: 50;
26
- color: rgb(255,255,255);
27
- }
28
-
29
- scrollbar {
30
- width: 25;
31
- control_height: 100;
32
- control_padding: 5;
33
- control_rounding: 5;
34
- }
35
- EOF
36
-
37
- template <<-EOF
38
- [template]
39
- hblock { @keypress="update_keys"}
40
- vblock
41
- hblock
42
- label#count {
43
- :content="count"
44
- size="130"
45
- :color="count_color"
46
- }
47
- hblock
48
- vblock#add { ...additionStyles }
49
- label {
50
- content="Add"
51
- @click="increment"
52
- ...additionLabel
4
+ module Demos
5
+ class Counter < Hokusai::Block
6
+ style <<~EOF
7
+ [style]
8
+ additionStyles {
9
+ background: rgb(214, 49, 24);
10
+ rounding: 0.0;
11
+ outline: outline(1,4,4,1);
12
+ outline_color: rgb(216, 26, 137);
13
+ }
14
+
15
+ additionLabel {
16
+ size: 40;
17
+ color: rgb(255,255,255);
18
+ }
19
+
20
+ subtractStyles {
21
+ background: rgb(0, 85, 170);
22
+ rounding: 0.0;
23
+ }
24
+
25
+ subtractLabel {
26
+ size: 50;
27
+ color: rgb(255,255,255);
28
+ }
29
+
30
+ scrollbar {
31
+ width: 25;
32
+ control_height: 100;
33
+ control_padding: 5;
34
+ control_rounding: 5;
35
+ }
36
+ EOF
37
+
38
+ template <<-EOF
39
+ [template]
40
+ hblock { @keypress="update_keys"}
41
+ vblock
42
+ hblock
43
+ label#count {
44
+ :content="count"
45
+ size="130"
46
+ :color="count_color"
53
47
  }
54
- vblock#subtract { ...subtractStyles }
55
- label {
56
- content="Subtract"
57
- @click="decrement"
58
- ...subtractLabel
59
- }
60
- [if="count_positive"]
61
- scrollbar { ...scrollbar }
62
- EOF
63
-
64
- uses(
65
- vblock: Hokusai::Blocks::Vblock,
66
- hblock: Hokusai::Blocks::Hblock,
67
- label: Hokusai::Blocks::Label,
68
- scrollbar: Hokusai::Blocks::Scrollbar,
69
- image: Hokusai::Blocks::Image
70
- )
71
-
72
- attr_accessor :count, :keys
73
-
74
- def count_positive
75
- count > 0
76
- end
77
-
78
- def modal
79
- !keys.empty?
80
- end
81
-
82
- def update_keys(event)
83
- @keys << event.char
84
- end
85
-
86
- def increment(event)
87
- self.count += 1
88
- end
89
-
90
- def decrement(event)
91
- self.count -= 1
92
- end
93
-
94
- def count_color
95
- self.count > 0 ? [0,0,255] : [255,0,0]
96
- end
97
-
98
- def initialize(**args)
99
- @count = 0
100
- @keys = ""
101
- super(**args)
48
+ hblock
49
+ vblock#add { ...additionStyles }
50
+ label {
51
+ content="Add"
52
+ @click="increment"
53
+ ...additionLabel
54
+ }
55
+ vblock#subtract { ...subtractStyles }
56
+ label {
57
+ content="Subtract"
58
+ @click="decrement"
59
+ ...subtractLabel
60
+ }
61
+ [if="count_positive"]
62
+ scrollbar { ...scrollbar }
63
+ EOF
64
+
65
+ uses(
66
+ vblock: Hokusai::Blocks::Vblock,
67
+ hblock: Hokusai::Blocks::Hblock,
68
+ label: Hokusai::Blocks::Label,
69
+ scrollbar: Hokusai::Blocks::Scrollbar,
70
+ image: Hokusai::Blocks::Image
71
+ )
72
+
73
+ attr_accessor :count, :keys
74
+
75
+ def count_positive
76
+ count > 0
77
+ end
78
+
79
+ def modal
80
+ !keys.empty?
81
+ end
82
+
83
+ def update_keys(event)
84
+ @keys << event.char
85
+ end
86
+
87
+ def increment(event)
88
+ self.count += 1
89
+ end
90
+
91
+ def decrement(event)
92
+ self.count -= 1
93
+ end
94
+
95
+ def count_color
96
+ self.count > 0 ? [0,0,255] : [255,0,0]
97
+ end
98
+
99
+ def initialize(**args)
100
+ @count = 0
101
+ @keys = ""
102
+ super(**args)
103
+ end
102
104
  end
103
105
  end
104
106
 
105
- Hokusai::Backends::RaylibBackend.run(Counter) do |config|
107
+ Hokusai::Backends::RaylibBackend.run(Demos::Counter) do |config|
106
108
  # config.after_load do
107
109
  # # Note: how to load a font...
108
110
  # # Thank you to Vladimir Nikolic - https://www.1001fonts.com/users/vladimirnikolic/
@@ -5,134 +5,136 @@ require_relative "../src/hokusai/backends/raylib"
5
5
  require_relative "./stock"
6
6
  require_relative "./tic_tac_toe"
7
7
 
8
- module Dynamic
9
- class Block < Hokusai::Block
10
- template <<~EOF
11
- [template]
12
- empty
13
- EOF
8
+ module Demos
9
+ module Dynamic
10
+ class Block < Hokusai::Block
11
+ template <<~EOF
12
+ [template]
13
+ empty
14
+ EOF
14
15
 
15
- uses(empty: Hokusai::Blocks::Empty)
16
+ uses(empty: Hokusai::Blocks::Empty)
16
17
 
17
- computed! :script
18
+ computed! :script
18
19
 
19
- def on_mounted
20
- klass = eval(script)
20
+ def on_mounted
21
+ klass = eval(script)
21
22
 
22
- raise Hokusai::Error.new("Class #{klass} is not a Hokusai::Block") unless klass.ancestors.include?(Hokusai::Block)
23
+ raise Hokusai::Error.new("Class #{klass} is not a Hokusai::Block") unless klass.ancestors.include?(Hokusai::Block)
23
24
 
24
- node.meta.set_child(0, klass.mount)
25
+ node.meta.set_child(0, klass.mount)
26
+ end
25
27
  end
26
- end
27
28
 
28
- class App < Hokusai::Block
29
- style <<~EOF
30
- [style]
31
- mainStyle {
32
- background: rgb(8, 8, 8);
33
- }
34
-
35
- appText {
36
- content: "Address Lookup";
37
- size: 30;
38
- color: rgb(222,222,222);
39
- }
40
- EOF
41
-
42
- template <<~EOF
43
- [template]
44
- vblock {
45
- ...mainStyle
29
+ class App < Hokusai::Block
30
+ style <<~EOF
31
+ [style]
32
+ mainStyle {
33
+ background: rgb(8, 8, 8);
46
34
  }
47
- text { ...appText }
48
- variable { :script="script" }
49
- EOF
50
-
51
- uses(
52
- vblock: Hokusai::Blocks::Vblock,
53
- text: Hokusai::Blocks::Text,
54
- variable: Dynamic::Block,
55
- )
56
-
57
- def script
58
- <<~RUBY
59
- require "rest-client"
60
- require "uri"
61
-
62
- class TestDynamic < Hokusai::Block
63
- style <<~EOF
64
- [style]
65
- inputStyle {
66
- background: rgb(18, 18, 18);
67
- text_color: rgb(244,244,244);
68
- size: 25;
69
- height: 80;
70
- outline: outline(1,0,1,0);
71
- outline_color: rgb(222,222,222);
72
- }
73
-
74
- textStyle {
75
- color: rgb(225, 228, 224);
76
- size: 23;
77
- cursor: "manual";
78
- padding: padding(5, 20, 0, 20);
79
- markdown: true;
80
- }
81
-
82
- buttonStyle {
83
- size: 20;
84
- content: "Open in Maps";
85
- }
86
- EOF
87
-
88
- template <<~EOF
89
- [template]
90
- input {
91
- ...inputStyle
92
- @change="geocode"
93
- }
94
- hblock
95
- [if="response"]
96
- panel
97
- text {
98
- ...textStyle
99
- :content="content"
100
- }
101
- EOF
102
-
103
- uses(
104
- hblock: Hokusai::Blocks::Hblock,
105
- text: Hokusai::Blocks::Text,
106
- input: Hokusai::Blocks::Input,
107
- panel: Hokusai::Blocks::Panel,
108
- button: Hokusai::Blocks::Button
109
- )
110
-
111
- attr_reader :response
112
-
113
- def geocode(address)
114
- uri = "https://geoffrey.skinnyjames.net/api/v1/us/geocode/\#{URI.encode_uri_component(address)}"
115
- @response = JSON.parse(RestClient.get(uri).body, symbolize_names: true)
116
- end
117
35
 
118
- def content
119
- @response&.reduce("") do |memo, payload|
120
- link = "https://maps.google.com/maps?q=\#{payload[:latitude]}+\#{payload[:longitude]}"
121
-
122
- memo << "Address: [\#{payload[:address_number]} \#{payload[:street_name]} (\#{payload[:postal_community]}, \#{payload[:state]})](\#{link})\n"
123
- memo << " **Latitude:** _\#{payload[:latitude]}_, **Longitude:** _\#{payload[:longitude]}_\n"
124
- memo << " [Some link](https://google.com)\n\n"
125
- end || "Placeholder"
36
+ appText {
37
+ content: "Address Lookup";
38
+ size: 30;
39
+ color: rgb(222,222,222);
40
+ }
41
+ EOF
42
+
43
+ template <<~EOF
44
+ [template]
45
+ vblock {
46
+ ...mainStyle
47
+ }
48
+ text { ...appText }
49
+ variable { :script="script" }
50
+ EOF
51
+
52
+ uses(
53
+ vblock: Hokusai::Blocks::Vblock,
54
+ text: Hokusai::Blocks::Text,
55
+ variable: Dynamic::Block,
56
+ )
57
+
58
+ def script
59
+ <<~RUBY
60
+ require "rest-client"
61
+ require "uri"
62
+
63
+ class TestDynamic < Hokusai::Block
64
+ style <<~EOF
65
+ [style]
66
+ inputStyle {
67
+ background: rgb(18, 18, 18);
68
+ text_color: rgb(244,244,244);
69
+ size: 25;
70
+ height: 80;
71
+ outline: outline(1,0,1,0);
72
+ outline_color: rgb(222,222,222);
73
+ }
74
+
75
+ textStyle {
76
+ color: rgb(225, 228, 224);
77
+ size: 23;
78
+ cursor: "manual";
79
+ padding: padding(5, 20, 0, 20);
80
+ markdown: true;
81
+ }
82
+
83
+ buttonStyle {
84
+ size: 20;
85
+ content: "Open in Maps";
86
+ }
87
+ EOF
88
+
89
+ template <<~EOF
90
+ [template]
91
+ input {
92
+ ...inputStyle
93
+ @change="geocode"
94
+ }
95
+ hblock
96
+ [if="response"]
97
+ panel
98
+ text {
99
+ ...textStyle
100
+ :content="content"
101
+ }
102
+ EOF
103
+
104
+ uses(
105
+ hblock: Hokusai::Blocks::Hblock,
106
+ text: Hokusai::Blocks::Text,
107
+ input: Hokusai::Blocks::Input,
108
+ panel: Hokusai::Blocks::Panel,
109
+ button: Hokusai::Blocks::Button
110
+ )
111
+
112
+ attr_reader :response
113
+
114
+ def geocode(address)
115
+ uri = "https://geoffrey.skinnyjames.net/api/v1/us/geocode/\#{URI.encode_uri_component(address)}"
116
+ @response = JSON.parse(RestClient.get(uri).body, symbolize_names: true)
117
+ end
118
+
119
+ def content
120
+ @response&.reduce("") do |memo, payload|
121
+ link = "https://maps.google.com/maps?q=\#{payload[:latitude]}+\#{payload[:longitude]}"
122
+
123
+ memo << "Address: [\#{payload[:address_number]} \#{payload[:street_name]} (\#{payload[:postal_community]}, \#{payload[:state]})](\#{link})\n"
124
+ memo << " **Latitude:** _\#{payload[:latitude]}_, **Longitude:** _\#{payload[:longitude]}_\n"
125
+ memo << " [Some link](https://google.com)\n\n"
126
+ end || "Placeholder"
127
+ end
126
128
  end
127
- end
128
129
 
129
- TestDynamic
130
- RUBY
130
+ TestDynamic
131
+ RUBY
132
+ end
131
133
  end
132
134
  end
133
135
  end
134
136
 
135
- Hokusai::Backends::SDLBackend.run(Dynamic::App) do |config|
137
+ Hokusai::Backends::SDLBackend.run(Demos::Dynamic::App) do |config|
136
138
  # backend specific configuration
137
139
  config.width = 600
138
140
  config.height = 500