hokusai-zero 0.1.2 → 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 +4 -2
- 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 -12
- 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 +5 -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/spec/hokusai/automation/keys_transcoder_spec.rb +5 -5
- data/ui/spec/hokusai/e2e/client_spec.rb +1 -0
- data/ui/spec/hokusai/e2e/meta_spec.rb +36 -36
- data/ui/spec/spec_helper.rb +13 -6
- 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
- data/xmake.lua +5 -4
- metadata +79 -3
@@ -45,6 +45,19 @@ class Hokusai::Blocks::Input < Hokusai::Block
|
|
45
45
|
@start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
46
46
|
@buffer_offset = 0
|
47
47
|
@offset = 0
|
48
|
+
@changed = false
|
49
|
+
end
|
50
|
+
|
51
|
+
def after_updated
|
52
|
+
if @changed && !growable
|
53
|
+
@table = ::Hokusai::Util::PieceTable.new(initial)
|
54
|
+
@buffer = ""
|
55
|
+
@buffer_count = 0
|
56
|
+
@start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
57
|
+
@buffer_offset = 0
|
58
|
+
@offset = 0
|
59
|
+
@changed = false
|
60
|
+
end
|
48
61
|
end
|
49
62
|
|
50
63
|
def update_height(value)
|
@@ -74,6 +87,7 @@ class Hokusai::Blocks::Input < Hokusai::Block
|
|
74
87
|
end
|
75
88
|
|
76
89
|
def dynamic_keypress_handle(event)
|
90
|
+
return unless node.meta.focused
|
77
91
|
case event
|
78
92
|
when proc(&:ctrl), proc(&:super)
|
79
93
|
if event.char == "z"
|
@@ -116,6 +130,7 @@ class Hokusai::Blocks::Input < Hokusai::Block
|
|
116
130
|
flush
|
117
131
|
|
118
132
|
emit("change", table.to_s)
|
133
|
+
@changed = true
|
119
134
|
|
120
135
|
self.table = ::Hokusai::Util::PieceTable.new("")
|
121
136
|
self.buffer_offset = 0
|
@@ -142,6 +157,8 @@ class Hokusai::Blocks::Input < Hokusai::Block
|
|
142
157
|
self.buffer += event.char
|
143
158
|
end
|
144
159
|
end
|
160
|
+
|
161
|
+
emit("modified")
|
145
162
|
end
|
146
163
|
|
147
164
|
def flush
|
@@ -6,6 +6,7 @@ class Hokusai::Blocks::Label < Hokusai::Block
|
|
6
6
|
EOF
|
7
7
|
|
8
8
|
computed! :content
|
9
|
+
computed :font, default: nil
|
9
10
|
computed :size, default: 12
|
10
11
|
computed :color, default: [33,33,33], convert: Hokusai::Color
|
11
12
|
computed :padding, default: [5.0, 5.0, 5.0, 5.0], convert: Hokusai::Padding
|
@@ -21,8 +22,9 @@ class Hokusai::Blocks::Label < Hokusai::Block
|
|
21
22
|
|
22
23
|
def render(canvas)
|
23
24
|
if @last_content != content
|
24
|
-
width,
|
25
|
-
|
25
|
+
width, height = Hokusai.fonts.active.measure(content.to_s, size.to_i)
|
26
|
+
node.meta.set_prop(:width, width + padding.right + padding.left)
|
27
|
+
node.meta.set_prop(:height, height + padding.top + padding.bottom)
|
26
28
|
emit("width_updated", width + padding.right + padding.left)
|
27
29
|
|
28
30
|
@last_content = content
|
@@ -33,6 +35,7 @@ class Hokusai::Blocks::Label < Hokusai::Block
|
|
33
35
|
command.color = color
|
34
36
|
command.size = size
|
35
37
|
command.padding = padding
|
38
|
+
command.font = font unless font.nil?
|
36
39
|
end
|
37
40
|
end
|
38
41
|
end
|
@@ -15,13 +15,14 @@ class Hokusai::Blocks::Text < Hokusai::Block
|
|
15
15
|
uses(empty: Hokusai::Blocks::Empty)
|
16
16
|
|
17
17
|
computed! :content
|
18
|
+
computed :font, default: nil
|
18
19
|
computed :size, default: 16, convert: proc(&:to_i)
|
19
20
|
computed :line_height, default: 5, convert: proc(&:to_f)
|
20
21
|
computed :color, default: [33,33,33], convert: Hokusai::Color
|
21
22
|
computed :selection_color, default: [233,233,233], convert: Hokusai::Color
|
22
23
|
computed :padding, default: [5.0, 5.0, 5.0, 5.0], convert: Hokusai::Padding
|
23
24
|
computed :cursor_offset, default: nil
|
24
|
-
computed :markdown, default: false
|
25
|
+
computed :markdown, default: false, convert: ->(val) { val == "true" || val == true }
|
25
26
|
|
26
27
|
inject :selection
|
27
28
|
inject :panel_top
|
@@ -65,7 +66,6 @@ class Hokusai::Blocks::Text < Hokusai::Block
|
|
65
66
|
|
66
67
|
draw_with do |commands|
|
67
68
|
iterator.on_draw do |text, x, y, group|
|
68
|
-
|
69
69
|
if selector = selection
|
70
70
|
if cursor_offset&.zero? && !selector.started
|
71
71
|
selector.cursor = [x, y + offset_y, 0.0, size.to_f]
|
@@ -86,6 +86,7 @@ class Hokusai::Blocks::Text < Hokusai::Block
|
|
86
86
|
commands.text(text, x, y) do |command|
|
87
87
|
command.color = color
|
88
88
|
command.size = size
|
89
|
+
command.font = font unless font.nil?
|
89
90
|
|
90
91
|
if group.respond_to?(:bold?)
|
91
92
|
|
@@ -186,7 +187,8 @@ class Hokusai::Blocks::Text < Hokusai::Block
|
|
186
187
|
|
187
188
|
def clamp(text, width)
|
188
189
|
if markdown
|
189
|
-
Hokusai.fonts.active.clamp_markdown(text, size.to_i, width - size.to_f - padding.right)
|
190
|
+
clamping = Hokusai.fonts.active.clamp_markdown(text, size.to_i, width - size.to_f - padding.right)
|
191
|
+
clamping
|
190
192
|
else
|
191
193
|
Hokusai.fonts.active.clamp(text, size.to_i, width - size.to_f, padding.right)
|
192
194
|
end
|
@@ -203,10 +205,13 @@ class Hokusai::Blocks::Text < Hokusai::Block
|
|
203
205
|
|
204
206
|
height = internal_render(last_clamping, canvas)
|
205
207
|
self.last_content = last_content
|
206
|
-
|
208
|
+
|
209
|
+
new_height = height + padding.bottom + padding.top
|
210
|
+
new_height -= size if markdown
|
207
211
|
|
208
|
-
|
212
|
+
emit("height_updated", new_height) unless last_height == new_height
|
209
213
|
|
214
|
+
self.last_height = new_height
|
210
215
|
|
211
216
|
yield canvas
|
212
217
|
end
|
@@ -32,12 +32,12 @@ module Hokusai::Blocks::Titlebar
|
|
32
32
|
EOF
|
33
33
|
|
34
34
|
computed :rounding, default: 0.0, convert: proc(&:to_f)
|
35
|
-
computed :outline, default:
|
36
|
-
computed :outline_color, default:
|
35
|
+
computed :outline, default: nil
|
36
|
+
computed :outline_color, default: nil
|
37
37
|
computed :unhovered_color, default: DEFAULT, convert: Hokusai::Color
|
38
38
|
computed :radius, default: 6.0, convert: proc(&:to_f)
|
39
|
-
computed :background, default: nil
|
40
|
-
computed :background_drag, default: nil
|
39
|
+
computed :background, default: nil
|
40
|
+
computed :background_drag, default: nil
|
41
41
|
|
42
42
|
|
43
43
|
uses(
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Hokusai::Blocks::Variable < Hokusai::Block
|
2
|
+
template <<~EOF
|
3
|
+
[template]
|
4
|
+
empty
|
5
|
+
EOF
|
6
|
+
|
7
|
+
uses(empty: Hokusai::Blocks::Empty)
|
8
|
+
|
9
|
+
computed! :script
|
10
|
+
|
11
|
+
def after_updated
|
12
|
+
if @last_height != children[0].node.meta.get_prop(:height)
|
13
|
+
@last_height = children[0].node.meta.get_prop(:height)
|
14
|
+
|
15
|
+
node.meta.set_prop(:height, @last_height)
|
16
|
+
emit("height_updated", @last_height)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_mounted
|
21
|
+
klass = eval(script)
|
22
|
+
|
23
|
+
raise Hokusai::Error.new("Class #{klass} is not a Hokusai::Block") unless klass.ancestors.include?(Hokusai::Block)
|
24
|
+
|
25
|
+
node.meta.set_child(0, klass.mount)
|
26
|
+
end
|
27
|
+
|
28
|
+
def render(canvas)
|
29
|
+
if Hokusai.can_render(canvas)
|
30
|
+
yield canvas
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -26,10 +26,10 @@ module Hokusai
|
|
26
26
|
def trim_canvas(canvas)
|
27
27
|
x, y, w, h = background_boundary
|
28
28
|
|
29
|
-
canvas.x = x + padding.left
|
30
|
-
canvas.y = y + padding.top
|
31
|
-
canvas.width = w - (padding.left + padding.right)
|
32
|
-
canvas.height = h - (padding.top + padding.bottom)
|
29
|
+
canvas.x = x + padding.left + outline.left
|
30
|
+
canvas.y = y + padding.top + outline.top
|
31
|
+
canvas.width = w - (padding.left + padding.right + outline.left + outline.right)
|
32
|
+
canvas.height = h - (padding.top + padding.bottom + outline.top + outline.bottom)
|
33
33
|
|
34
34
|
canvas
|
35
35
|
end
|
data/ui/src/hokusai/commands.rb
CHANGED
@@ -6,82 +6,84 @@ require_relative "./commands/scissor"
|
|
6
6
|
require_relative "./commands/text"
|
7
7
|
|
8
8
|
module Hokusai
|
9
|
+
# A proxy class for invoking various UI commands
|
10
|
+
#
|
11
|
+
# Invocations of commands are immediately sent to the backend
|
12
|
+
# for drawing
|
13
|
+
#
|
14
|
+
# Used as part of the drawing api for Hokusai::Block
|
9
15
|
class Commands
|
10
16
|
attr_reader :queue
|
11
17
|
|
12
|
-
def initialize
|
13
|
-
# @queue = []
|
14
|
-
end
|
15
|
-
|
16
|
-
# def hash
|
17
|
-
# [self.class, *@queue.map(&:hash)].hash
|
18
|
-
# end
|
18
|
+
def initialize; end
|
19
19
|
|
20
|
+
# Draw a rectangle
|
21
|
+
#
|
22
|
+
# @param [Float] the x coordinate
|
23
|
+
# @param [Float] the y coordinate
|
24
|
+
# @param [Float] the width of the rectangle
|
25
|
+
# @param [Float] height of the rectangle
|
20
26
|
def rect(x, y, w, h)
|
21
27
|
command = Commands::Rect.new(x, y, w, h)
|
28
|
+
|
22
29
|
yield(command)
|
23
30
|
|
24
31
|
command.draw
|
25
|
-
# add(command)
|
26
32
|
end
|
27
33
|
|
34
|
+
# Draw a circle
|
35
|
+
#
|
36
|
+
# @param [Float] x coordinate
|
37
|
+
# @param [Float] y coordinate
|
38
|
+
# @param [Float] radius of the circle
|
28
39
|
def circle(x, y, radius)
|
29
40
|
command = Commands::Circle.new(x, y, radius)
|
41
|
+
|
30
42
|
yield(command)
|
31
43
|
|
32
44
|
command.draw
|
33
|
-
# add(command)
|
34
45
|
end
|
35
46
|
|
47
|
+
# Draws an SVG
|
48
|
+
#
|
49
|
+
# @param [String] location of the svg
|
50
|
+
# @param [Float] x coord
|
51
|
+
# @param [Float] y coord
|
52
|
+
# @param [Float] width of the svg
|
53
|
+
# @param [Float] height of the svg
|
36
54
|
def svg(source, x, y, w, h)
|
37
55
|
command = Commands::SVG.new(source, x, y, w, h)
|
38
|
-
yield(command)
|
39
56
|
|
40
|
-
|
57
|
+
yield(command)
|
41
58
|
end
|
42
59
|
|
43
60
|
# Invokes an image command
|
44
61
|
# from a filename, at position {x,y} with `w`x`h` dimensions
|
45
62
|
def image(source, x, y, w, h)
|
46
63
|
Commands::Image.new(source, x, y, w, h).draw
|
47
|
-
# add(Commands::Image.new(source, x, y, w, h))
|
48
64
|
end
|
49
65
|
|
50
66
|
# Invokes a scissor begin command
|
51
67
|
# at position {x,y} with `w`x`h` dimensions
|
52
68
|
def scissor_begin(x, y, w, h)
|
53
69
|
Commands::ScissorBegin.new(x, y, w, h).draw
|
54
|
-
# add(Commands::ScissorBegin.new(x, y, w, h))
|
55
70
|
end
|
56
71
|
|
57
72
|
# Invokes a scissor stop command
|
58
73
|
def scissor_end
|
59
74
|
Commands::ScissorEnd.new.draw
|
60
|
-
# add(Commands::ScissorEnd.new)
|
61
75
|
end
|
62
76
|
|
77
|
+
# Draws text
|
78
|
+
#
|
79
|
+
# @param [String] the text content
|
80
|
+
# @param [Float] x coord
|
81
|
+
# @param [Float] y coord
|
63
82
|
def text(content, x, y)
|
64
83
|
command = Commands::Text.new(content, x, y)
|
65
84
|
yield command
|
66
85
|
|
67
86
|
command.draw
|
68
|
-
# add(command)
|
69
|
-
end
|
70
|
-
|
71
|
-
def each
|
72
|
-
queue.each do |cmd|
|
73
|
-
yield(cmd)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def clear!
|
78
|
-
# @queue = []
|
79
|
-
end
|
80
|
-
|
81
|
-
def add(command)
|
82
|
-
# @queue << command
|
83
|
-
|
84
|
-
self
|
85
87
|
end
|
86
88
|
end
|
87
89
|
end
|
data/ui/src/hokusai/diff.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module Hokusai
|
2
|
+
# Represents a patch to move a loop item
|
3
|
+
# from one location to another
|
2
4
|
class MovePatch
|
3
5
|
attr_accessor :from, :to, :delete
|
4
6
|
|
@@ -9,6 +11,8 @@ module Hokusai
|
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
14
|
+
# Represents a patch to insert an item
|
15
|
+
# into the loop list
|
12
16
|
class InsertPatch
|
13
17
|
attr_accessor :target, :value, :delete
|
14
18
|
|
@@ -19,6 +23,8 @@ module Hokusai
|
|
19
23
|
end
|
20
24
|
end
|
21
25
|
|
26
|
+
# Represents a patch to update the value
|
27
|
+
# of a loop item at an index
|
22
28
|
class UpdatePatch
|
23
29
|
attr_accessor :target, :value
|
24
30
|
|
@@ -28,6 +34,7 @@ module Hokusai
|
|
28
34
|
end
|
29
35
|
end
|
30
36
|
|
37
|
+
# Patch to delete a loop list item
|
31
38
|
class DeletePatch
|
32
39
|
attr_accessor :target
|
33
40
|
|
@@ -36,6 +43,10 @@ module Hokusai
|
|
36
43
|
end
|
37
44
|
end
|
38
45
|
|
46
|
+
# A Differ for comparing one set of values to another
|
47
|
+
#
|
48
|
+
# When #patch is called, will yield various patches to
|
49
|
+
# true up the old values with the new values.
|
39
50
|
class Diff
|
40
51
|
attr_reader :before, :after, :insertions
|
41
52
|
|
data/ui/src/hokusai/event.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Hokusai
|
4
|
+
# A Basic UI Event
|
4
5
|
class Event
|
5
|
-
attr_reader :captures
|
6
|
+
attr_reader :captures
|
6
7
|
attr_accessor :stopped
|
7
8
|
|
9
|
+
# Sets the name of this event kind
|
8
10
|
def self.name(name)
|
9
11
|
@name = name
|
10
12
|
end
|
@@ -13,33 +15,45 @@ module Hokusai
|
|
13
15
|
self.class.instance_variable_get("@name")
|
14
16
|
end
|
15
17
|
|
18
|
+
# Has the event stopped propagation?
|
19
|
+
# @return [Bool]
|
16
20
|
def stopped
|
17
21
|
@stopped ||= false
|
18
22
|
end
|
19
23
|
|
24
|
+
# Stop propagation on this event
|
25
|
+
# @return [Void]
|
20
26
|
def stop
|
21
27
|
self.stopped = true
|
22
28
|
end
|
23
29
|
|
30
|
+
# @return [Array<Block>] the captured blocks for this event
|
24
31
|
def captures
|
25
32
|
@captures ||= []
|
26
33
|
end
|
27
34
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
35
|
+
# A JSON string representing this event
|
36
|
+
#
|
37
|
+
# Used in automation
|
38
|
+
# @return [String]
|
32
39
|
def to_json
|
33
40
|
raise Hokusai::Error.new("#{self.class} must implement to_json")
|
34
41
|
end
|
35
42
|
|
43
|
+
# Does the event match the provided Hokusai::Block?
|
44
|
+
#
|
45
|
+
# @param [Hokusai::Block]
|
46
|
+
# @return [Bool]
|
36
47
|
def matches(block)
|
37
48
|
return false if block.node.portal.nil?
|
38
49
|
|
39
50
|
val = block.node.portal.ast.event(name)
|
51
|
+
|
40
52
|
!!val
|
41
53
|
end
|
42
54
|
|
55
|
+
# Emit the event to all captured blocks,
|
56
|
+
# stopping if any of the blocks stop propagation
|
43
57
|
def bubble
|
44
58
|
while block = captures.pop
|
45
59
|
block.emit(name, self)
|
@@ -165,8 +165,16 @@ module Hokusai
|
|
165
165
|
class MouseOutEvent < MouseEvent
|
166
166
|
name "mouseout"
|
167
167
|
|
168
|
-
def capture(block,
|
168
|
+
def capture(block, canvas)
|
169
169
|
captures << block if matches(block)
|
170
|
+
|
171
|
+
if left[:clicked] && !clicked(canvas)
|
172
|
+
block.node.meta.blur
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def clicked(canvas)
|
177
|
+
LibHokusai.hoku_input_is_clicked(input.raw, canvas.to_hoku_rect)
|
170
178
|
end
|
171
179
|
end
|
172
180
|
end
|
data/ui/src/hokusai/font.rb
CHANGED
@@ -1,29 +1,54 @@
|
|
1
1
|
module Hokusai
|
2
|
+
# A Backend agnostic font interface
|
3
|
+
#
|
4
|
+
# Backends are expected to implement the following methods
|
2
5
|
class Font
|
6
|
+
# Creates a wrapping of text based on container width and font size
|
7
|
+
#
|
8
|
+
# @param [String] the text to wrap
|
9
|
+
# @param [Integer] the font size
|
10
|
+
# @param [Float] the width of the container
|
11
|
+
# @param [Float] an initital offset
|
12
|
+
# @return [Hokusai::Clamping]
|
3
13
|
def clamp(text, size, width, initial_offset = 0.0)
|
4
14
|
raise Hokusai::Error.new("Font #clamp not implemented")
|
5
15
|
end
|
6
16
|
|
17
|
+
# Creates a wrapping of text based on the container width and font size
|
18
|
+
# and parses markdown
|
19
|
+
# @param [String] the text to wrap
|
20
|
+
# @param [Integer] the font size
|
21
|
+
# @param [Float] the width of the container
|
22
|
+
# @param [Float] an initital offset
|
23
|
+
# @return [Hokusai::Clamping]
|
7
24
|
def clamp_markdown(text, size, width, initial_offset = 0.0)
|
8
25
|
raise Hokusai::Error.new("Font #clamp not implemented")
|
9
26
|
end
|
10
27
|
|
28
|
+
# @return [Integer] the font height
|
11
29
|
def height
|
12
30
|
raise Hokusai::Error.new("Font #height not implemented")
|
13
31
|
end
|
14
32
|
end
|
15
33
|
|
34
|
+
# A class representing wrapped text
|
35
|
+
#
|
36
|
+
# A clamping has many segments, delimited by a newline
|
37
|
+
# A segment has many possible groups, and a group has many possible charss
|
16
38
|
class Clamping
|
17
39
|
class Char
|
18
40
|
attr_reader :raw
|
41
|
+
|
19
42
|
def initialize(raw)
|
20
43
|
@raw = raw
|
21
44
|
end
|
22
45
|
|
46
|
+
# @return [Float] the width of the char
|
23
47
|
def width
|
24
48
|
raw[:width]
|
25
49
|
end
|
26
50
|
|
51
|
+
# @return [Integer] the offset of the char relative to the clamping
|
27
52
|
def offset
|
28
53
|
raw[:offset]
|
29
54
|
end
|
@@ -36,46 +61,57 @@ module Hokusai
|
|
36
61
|
@raw = raw
|
37
62
|
end
|
38
63
|
|
64
|
+
# @return [Integer] the offset of the group relative to the clamping
|
39
65
|
def offset
|
40
66
|
@offset ||= raw[:offset]
|
41
67
|
end
|
42
68
|
|
69
|
+
# @return [Integer] number of chars in this group
|
43
70
|
def size
|
44
71
|
@size ||= raw[:size]
|
45
72
|
end
|
46
73
|
|
74
|
+
# @return [Float] the total width of chars in this group
|
47
75
|
def width
|
48
76
|
chars.sum(&:width)
|
49
77
|
end
|
50
78
|
|
79
|
+
# @return [UInt] a flag for this group type
|
51
80
|
def type
|
52
81
|
@type ||= raw[:type]
|
53
82
|
end
|
54
83
|
|
84
|
+
# @return [Bool] is this group normal?
|
55
85
|
def normal?
|
56
86
|
@normal ||= type == LibHokusai::GROUP_NORMAL
|
57
87
|
end
|
58
88
|
|
89
|
+
# @return [Bool] is this group bold?
|
59
90
|
def bold?
|
60
91
|
@bold ||= ((type & LibHokusai::GROUP_BOLD) != 0)
|
61
92
|
end
|
62
93
|
|
94
|
+
# @return [Bool] is this group italics?
|
63
95
|
def italics?
|
64
96
|
@italics ||= ((type & LibHokusai::GROUP_ITALICS) != 0)
|
65
97
|
end
|
66
98
|
|
99
|
+
# @return [Bool] does this group represent a hyperlink?
|
67
100
|
def link?
|
68
101
|
@link ||= ((type & LibHokusai::GROUP_LINK) != 0)
|
69
102
|
end
|
70
103
|
|
104
|
+
# @return [Bool] does this group represent a code block?
|
71
105
|
def code?
|
72
106
|
@code ||= type & LibHokusai::GROUP_CODE
|
73
107
|
end
|
74
108
|
|
109
|
+
# @return [String] the hyperlink for this group if there is one
|
75
110
|
def link
|
76
111
|
@href ||= raw[:payload].read_string
|
77
112
|
end
|
78
113
|
|
114
|
+
# @return [Array<Hokusai::Char>] an array of chars
|
79
115
|
def chars
|
80
116
|
return @chars unless @chars.nil?
|
81
117
|
|
@@ -106,18 +142,23 @@ module Hokusai
|
|
106
142
|
@raw = raw
|
107
143
|
end
|
108
144
|
|
145
|
+
# A segment width given a range of offsets
|
146
|
+
# NOTE: Defaults to the full segment
|
109
147
|
def width(range = (offset...offset + size))
|
110
148
|
chars[range]&.sum(&:width) || 0.0
|
111
149
|
end
|
112
150
|
|
151
|
+
# @return [Integer] the offset of this segment relative to the clamping
|
113
152
|
def offset
|
114
153
|
raw[:offset]
|
115
154
|
end
|
116
155
|
|
156
|
+
# @return [Integer] the number of chars in this segment
|
117
157
|
def size
|
118
158
|
raw[:size]
|
119
159
|
end
|
120
160
|
|
161
|
+
# @return [Array<Hokusai::Char>] an array of chars
|
121
162
|
def chars
|
122
163
|
return @chars unless @chars.nil?
|
123
164
|
|
@@ -140,6 +181,7 @@ module Hokusai
|
|
140
181
|
end
|
141
182
|
end
|
142
183
|
|
184
|
+
# @return [Array<Hokusai::Group>] an array of clamping groups
|
143
185
|
def groups
|
144
186
|
return @groups unless @groups.nil?
|
145
187
|
|
@@ -243,6 +285,7 @@ module Hokusai
|
|
243
285
|
end
|
244
286
|
end
|
245
287
|
|
288
|
+
# Keeps track of any loaded fonts
|
246
289
|
class FontRegistry
|
247
290
|
attr_reader :fonts, :active_font
|
248
291
|
|
@@ -251,28 +294,45 @@ module Hokusai
|
|
251
294
|
@active_font = nil
|
252
295
|
end
|
253
296
|
|
297
|
+
# Registers a font
|
298
|
+
#
|
299
|
+
# @param [String] the name of the font
|
300
|
+
# @param [Hokusai::Font] a font
|
254
301
|
def register(name, font)
|
255
302
|
raise Hokusai::Error.new("Font #{name} already registered") if fonts[name]
|
256
303
|
|
257
304
|
fonts[name] = font
|
258
305
|
end
|
259
306
|
|
307
|
+
# Returns the active font's name
|
308
|
+
#
|
309
|
+
# @return [String]
|
260
310
|
def active_font_name
|
261
311
|
raise Hokusai::Error.new("No active font") if active_font.nil?
|
262
312
|
|
263
313
|
active_font
|
264
314
|
end
|
265
315
|
|
316
|
+
# Activates a font by name
|
317
|
+
#
|
318
|
+
# @param [String] the name of the registered font
|
266
319
|
def activate(name)
|
267
320
|
raise Hokusai::Error.new("Font #{name} is not registered") unless fonts[name]
|
268
321
|
|
269
322
|
@active_font = name
|
270
323
|
end
|
271
324
|
|
325
|
+
# Fetches a font
|
326
|
+
#
|
327
|
+
# @param [String] the name of the registered font
|
328
|
+
# @return [Hokusai::Font]
|
272
329
|
def get(name)
|
273
330
|
fonts[name]
|
274
331
|
end
|
275
332
|
|
333
|
+
# Fetches the active font
|
334
|
+
#
|
335
|
+
# @return [Hokusai::Font]
|
276
336
|
def active
|
277
337
|
fonts[active_font]
|
278
338
|
end
|
data/ui/src/hokusai/meta.rb
CHANGED
@@ -105,24 +105,18 @@ module Hokusai
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def update(block)
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
if updater_block = updater
|
112
|
-
# Hokusai::Pool.post do
|
113
|
-
block.public_send(:before_updated) if block.respond_to?(:before_updated)
|
114
|
-
|
115
|
-
updater_block.call(block, target_block, target_block)
|
116
|
-
block.public_send(:after_updated) if block.respond_to?(:after_updated)
|
117
|
-
|
118
|
-
# end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
# end
|
108
|
+
if target_block = target
|
109
|
+
if updater_block = updater
|
110
|
+
block.public_send(:before_updated) if block.respond_to?(:before_updated)
|
122
111
|
|
123
|
-
|
124
|
-
|
112
|
+
updater_block.call(block, target_block, target_block)
|
113
|
+
block.public_send(:after_updated) if block.respond_to?(:after_updated)
|
125
114
|
end
|
115
|
+
end
|
116
|
+
|
117
|
+
children?&.each do |child|
|
118
|
+
child.update
|
119
|
+
end
|
126
120
|
end
|
127
121
|
|
128
122
|
def has_ast?(ast, index)
|