hokusai-zero 0.1.1
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 +7 -0
- data/Dockerfile +26 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +91 -0
- data/LICENSE +21 -0
- data/README.md +28 -0
- data/ast/genheader +3 -0
- data/ast/include/hashmap.c +1151 -0
- data/ast/include/hashmap.c.license +20 -0
- data/ast/include/hashmap.h +54 -0
- data/ast/src/core/ast.c +448 -0
- data/ast/src/core/ast.h +259 -0
- data/ast/src/core/common.h +24 -0
- data/ast/src/core/component.c +85 -0
- data/ast/src/core/component.h +35 -0
- data/ast/src/core/hml.c +665 -0
- data/ast/src/core/hml.h +11 -0
- data/ast/src/core/input.c +458 -0
- data/ast/src/core/input.h +118 -0
- data/ast/src/core/style.c +101 -0
- data/ast/src/core/style.h +41 -0
- data/ast/src/core/text.c +784 -0
- data/ast/src/core/text.h +93 -0
- data/ast/src/core/util.c +140 -0
- data/ast/src/core/util.h +48 -0
- data/ast/src/hokusai.c +6 -0
- data/ast/src/hokusai.h +6 -0
- data/ast/test/fixtures/test.ui +13 -0
- data/ast/test/greatest.h +1266 -0
- data/ast/test/hokusai.c +14 -0
- data/ast/test/parser.c +234 -0
- data/ast/test/text.c +116 -0
- data/ext/extconf.rb +27 -0
- data/grammar/Cargo.lock +80 -0
- data/grammar/Cargo.toml +26 -0
- data/grammar/binding.gyp +20 -0
- data/grammar/bindings/node/binding.cc +28 -0
- data/grammar/bindings/node/index.js +19 -0
- data/grammar/bindings/rust/build.rs +40 -0
- data/grammar/bindings/rust/lib.rs +52 -0
- data/grammar/corpus/1_document.txt +131 -0
- data/grammar/corpus/2_selectors.txt +58 -0
- data/grammar/corpus/3_spaces.txt +69 -0
- data/grammar/corpus/4_errors.txt +10 -0
- data/grammar/corpus/5_macros.txt +175 -0
- data/grammar/corpus/6_styles.txt +81 -0
- data/grammar/grammar.js +275 -0
- data/grammar/package-lock.json +34 -0
- data/grammar/package.json +33 -0
- data/grammar/src/grammar.json +1269 -0
- data/grammar/src/node-types.json +474 -0
- data/grammar/src/parser.c +5772 -0
- data/grammar/src/scanner.c +258 -0
- data/grammar/src/tree_sitter/parser.h +230 -0
- data/grammar/src/tree_sitter/scanner.h +12 -0
- data/grammar/test.nml +10 -0
- data/hokusai.gemspec +19 -0
- data/ui/examples/assets/DigitalDisplay.ttf +0 -0
- data/ui/examples/assets/OpenSans-Regular.ttf +0 -0
- data/ui/examples/assets/addy.png +0 -0
- data/ui/examples/assets/baby_sean.png +0 -0
- data/ui/examples/assets/football-troll.png +0 -0
- data/ui/examples/assets/gear.png +0 -0
- data/ui/examples/assets/icecold.ttf +0 -0
- data/ui/examples/assets/science-troll.png +0 -0
- data/ui/examples/buddy.rb +31 -0
- data/ui/examples/clock.rb +58 -0
- data/ui/examples/counter.rb +123 -0
- data/ui/examples/dynamic.rb +147 -0
- data/ui/examples/foobar.rb +236 -0
- data/ui/examples/stock.rb +115 -0
- data/ui/examples/stock_decider/option.rb +74 -0
- data/ui/examples/tic_tac_toe.rb +246 -0
- data/ui/lib/lib_hokusai.rb +425 -0
- data/ui/spec/hokusai/ast_spec.rb +88 -0
- data/ui/spec/hokusai/automation/keys_transcoder_spec.rb +50 -0
- data/ui/spec/hokusai/automation/selector_spec.rb +68 -0
- data/ui/spec/hokusai/block_spec.rb +126 -0
- data/ui/spec/hokusai/directives_spec.rb +327 -0
- data/ui/spec/hokusai/e2e/client_spec.rb +58 -0
- data/ui/spec/hokusai/e2e/meta_spec.rb +42 -0
- data/ui/spec/hokusai/publisher_spec.rb +38 -0
- data/ui/spec/hokusai/slots_spec.rb +150 -0
- data/ui/spec/hokusai/util/piece_table_spec.rb +90 -0
- data/ui/spec/hokusai_spec.rb +0 -0
- data/ui/spec/spec_helper.rb +30 -0
- data/ui/src/hokusai/ast.rb +446 -0
- data/ui/src/hokusai/automation/client.rb +167 -0
- data/ui/src/hokusai/automation/constants.rb +98 -0
- data/ui/src/hokusai/automation/converters/selector_converter.rb +61 -0
- data/ui/src/hokusai/automation/driver.rb +54 -0
- data/ui/src/hokusai/automation/driver_command_queue.rb +50 -0
- data/ui/src/hokusai/automation/driver_commands/base.rb +79 -0
- data/ui/src/hokusai/automation/driver_commands/get_attribute.rb +41 -0
- data/ui/src/hokusai/automation/driver_commands/invoke.rb +33 -0
- data/ui/src/hokusai/automation/driver_commands/locate.rb +48 -0
- data/ui/src/hokusai/automation/driver_commands/trigger_keyboard.rb +94 -0
- data/ui/src/hokusai/automation/driver_commands/trigger_mouse.rb +213 -0
- data/ui/src/hokusai/automation/keys_transcoder.rb +128 -0
- data/ui/src/hokusai/automation/selector.rb +39 -0
- data/ui/src/hokusai/automation/server.rb +114 -0
- data/ui/src/hokusai/automation.rb +3 -0
- data/ui/src/hokusai/backends/raylib/config.rb +47 -0
- data/ui/src/hokusai/backends/raylib/font.rb +113 -0
- data/ui/src/hokusai/backends/raylib/keys.rb +124 -0
- data/ui/src/hokusai/backends/raylib.rb +449 -0
- data/ui/src/hokusai/backends/sdl2/Monaco.ttf +0 -0
- data/ui/src/hokusai/backends/sdl2/color.rb +12 -0
- data/ui/src/hokusai/backends/sdl2/config.rb +31 -0
- data/ui/src/hokusai/backends/sdl2/font.rb +127 -0
- data/ui/src/hokusai/backends/sdl2/keys.rb +119 -0
- data/ui/src/hokusai/backends/sdl2.rb +529 -0
- data/ui/src/hokusai/block.rb +237 -0
- data/ui/src/hokusai/blocks/button.rb +100 -0
- data/ui/src/hokusai/blocks/checkbox.rb +51 -0
- data/ui/src/hokusai/blocks/circle.rb +28 -0
- data/ui/src/hokusai/blocks/clipped.rb +23 -0
- data/ui/src/hokusai/blocks/cursor.rb +49 -0
- data/ui/src/hokusai/blocks/dynamic.rb +37 -0
- data/ui/src/hokusai/blocks/empty.rb +10 -0
- data/ui/src/hokusai/blocks/hblock.rb +35 -0
- data/ui/src/hokusai/blocks/image.rb +18 -0
- data/ui/src/hokusai/blocks/input.rb +200 -0
- data/ui/src/hokusai/blocks/label.rb +39 -0
- data/ui/src/hokusai/blocks/panel.rb +126 -0
- data/ui/src/hokusai/blocks/rect.rb +24 -0
- data/ui/src/hokusai/blocks/scissor_begin.rb +18 -0
- data/ui/src/hokusai/blocks/scissor_end.rb +12 -0
- data/ui/src/hokusai/blocks/scrollbar.rb +103 -0
- data/ui/src/hokusai/blocks/selectable.rb +77 -0
- data/ui/src/hokusai/blocks/svg.rb +20 -0
- data/ui/src/hokusai/blocks/text.rb +214 -0
- data/ui/src/hokusai/blocks/titlebar/osx.rb +145 -0
- data/ui/src/hokusai/blocks/toggle.rb +55 -0
- data/ui/src/hokusai/blocks/vblock.rb +35 -0
- data/ui/src/hokusai/commands/base.rb +22 -0
- data/ui/src/hokusai/commands/circle.rb +47 -0
- data/ui/src/hokusai/commands/image.rb +45 -0
- data/ui/src/hokusai/commands/rect.rb +158 -0
- data/ui/src/hokusai/commands/scissor.rb +22 -0
- data/ui/src/hokusai/commands/text.rb +92 -0
- data/ui/src/hokusai/commands.rb +87 -0
- data/ui/src/hokusai/diff.rb +124 -0
- data/ui/src/hokusai/error.rb +3 -0
- data/ui/src/hokusai/event.rb +54 -0
- data/ui/src/hokusai/events/keyboard.rb +84 -0
- data/ui/src/hokusai/events/mouse.rb +172 -0
- data/ui/src/hokusai/font.rb +280 -0
- data/ui/src/hokusai/meta.rb +152 -0
- data/ui/src/hokusai/mounting/loop_entry.rb +230 -0
- data/ui/src/hokusai/mounting/mount_entry.rb +74 -0
- data/ui/src/hokusai/mounting/update_entry.rb +101 -0
- data/ui/src/hokusai/node.rb +98 -0
- data/ui/src/hokusai/node_mounter.rb +102 -0
- data/ui/src/hokusai/painter.rb +214 -0
- data/ui/src/hokusai/publisher.rb +32 -0
- data/ui/src/hokusai/style.rb +72 -0
- data/ui/src/hokusai/types.rb +266 -0
- data/ui/src/hokusai/util/clamping_iterator.rb +202 -0
- data/ui/src/hokusai/util/piece_table.rb +111 -0
- data/ui/src/hokusai/util/selection.rb +145 -0
- data/ui/src/hokusai.rb +120 -0
- data/ui/vendor/.gitkeep +0 -0
- data/vendor/.gitkeep +0 -0
- data/xmake.lua +192 -0
- metadata +222 -0
@@ -0,0 +1,128 @@
|
|
1
|
+
module Hokusai::Automation
|
2
|
+
module KeysTranscoder
|
3
|
+
KEYS = {
|
4
|
+
shift: "\ue008",
|
5
|
+
ctrl: "\ue009",
|
6
|
+
alt: "\ue00A",
|
7
|
+
super: "\ue03D",
|
8
|
+
lshift: "\ue008",
|
9
|
+
lctrl: "\ue009",
|
10
|
+
lalt: "\ue00A",
|
11
|
+
lsuper: "\ue03D",
|
12
|
+
rshift: "\ue050",
|
13
|
+
rctrl: "\ue051",
|
14
|
+
ralt: "\ue052",
|
15
|
+
rsuper: "\ue053",
|
16
|
+
enter: "\ue007",
|
17
|
+
tab: "\ue004",
|
18
|
+
backspace: "\ue003",
|
19
|
+
insert: "\ue016",
|
20
|
+
delete: "\ue017",
|
21
|
+
up: "\ue013",
|
22
|
+
right: "\ue014",
|
23
|
+
down: "\ue015",
|
24
|
+
left: "\ue012",
|
25
|
+
page_up: "\ue00E",
|
26
|
+
page_down: "\ue00F",
|
27
|
+
end: "\ue010",
|
28
|
+
home: "\ue011",
|
29
|
+
pause: "\ue00B",
|
30
|
+
escape: "\ue00C",
|
31
|
+
null: "\ue000",
|
32
|
+
cancel: "\ue001",
|
33
|
+
f1: "\ue031",
|
34
|
+
f2: "\ue032",
|
35
|
+
f3: "\ue033",
|
36
|
+
f4: "\ue034",
|
37
|
+
f5: "\ue035",
|
38
|
+
f6: "\ue036",
|
39
|
+
f7: "\ue037",
|
40
|
+
f8: "\ue038",
|
41
|
+
f9: "\ue039",
|
42
|
+
f10: "\ue03A",
|
43
|
+
f11: "\ue03B",
|
44
|
+
f12: "\ue03C",
|
45
|
+
kp0: "\ue01A",
|
46
|
+
kp1: "\ue01B",
|
47
|
+
kp2: "\ue01C",
|
48
|
+
kp3: "\ue01D",
|
49
|
+
kp4: "\ue01E",
|
50
|
+
kp5: "\ue01F",
|
51
|
+
kp6: "\ue020",
|
52
|
+
kp7: "\ue021",
|
53
|
+
kp8: "\ue022",
|
54
|
+
kp9: "\ue023",
|
55
|
+
multiply: "\ue024",
|
56
|
+
add: "\ue025",
|
57
|
+
separator: "\ue026",
|
58
|
+
subtract: "\ue027",
|
59
|
+
decimal: "\ue028",
|
60
|
+
divide: "\ue029",
|
61
|
+
equal: "\ue019",
|
62
|
+
caps_lock: "\ue054",
|
63
|
+
scroll_lock: "\ue055",
|
64
|
+
num_lock: "\ue056",
|
65
|
+
print_screen: "\ue057",
|
66
|
+
kb_menu: "\ue058",
|
67
|
+
back: "\ue059",
|
68
|
+
menu: "\ue05A",
|
69
|
+
volume_up: "\ue05B",
|
70
|
+
volume_down: "\ue05C",
|
71
|
+
}
|
72
|
+
|
73
|
+
REVERSE_KEYS = KEYS.invert
|
74
|
+
|
75
|
+
def self.[](key)
|
76
|
+
return KEYS[key] if KEYS[key]
|
77
|
+
|
78
|
+
raise Hokusai::Automation::Error.new("Unsupported key: #{key}")
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.decode(str)
|
82
|
+
parts = str.split("")
|
83
|
+
keys = []
|
84
|
+
prog = []
|
85
|
+
|
86
|
+
while part = parts.shift
|
87
|
+
|
88
|
+
if key = REVERSE_KEYS[part]
|
89
|
+
if key == :null
|
90
|
+
keys << prog
|
91
|
+
prog = []
|
92
|
+
else
|
93
|
+
prog << key
|
94
|
+
end
|
95
|
+
else
|
96
|
+
prog << part.to_s
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
keys.concat prog
|
101
|
+
keys
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.encode(keys)
|
105
|
+
keys.map { |key| encode_key(key) }.join("")
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.encode_key(key)
|
109
|
+
case key
|
110
|
+
when Symbol
|
111
|
+
self[key]
|
112
|
+
when Array
|
113
|
+
key = key.map do |e|
|
114
|
+
if e.is_a?(Symbol)
|
115
|
+
self[e]
|
116
|
+
else
|
117
|
+
e
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
key << self[:null]
|
122
|
+
key.join("")
|
123
|
+
else
|
124
|
+
key.to_s
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Hokusai::Automation
|
2
|
+
class Selector
|
3
|
+
attr_reader :node, :id, :class_list
|
4
|
+
|
5
|
+
def initialize(node, id, classes)
|
6
|
+
@node = node
|
7
|
+
@id = id
|
8
|
+
@class_list = classes || []
|
9
|
+
end
|
10
|
+
|
11
|
+
def matches(block)
|
12
|
+
if portal = block.node.portal
|
13
|
+
ast = portal.ast
|
14
|
+
|
15
|
+
matches = [[ast.type, node], [ast.id, id]].reduce(true) do |memo, (ast_property, target)|
|
16
|
+
next memo if target.nil?
|
17
|
+
|
18
|
+
target == ast_property && memo
|
19
|
+
end
|
20
|
+
|
21
|
+
return (class_list & ast.classes) == class_list && matches
|
22
|
+
end
|
23
|
+
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s(str = "")
|
28
|
+
classes_string = nil
|
29
|
+
|
30
|
+
unless class_list.empty?
|
31
|
+
classes_string = ".#{class_list.join(".")}"
|
32
|
+
|
33
|
+
str << "#{node || ""}##{id || ""}#{classes_string || ""}"
|
34
|
+
end
|
35
|
+
|
36
|
+
str
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rack"
|
4
|
+
require "thin"
|
5
|
+
require "ostruct"
|
6
|
+
require_relative "./driver"
|
7
|
+
require_relative "./constants"
|
8
|
+
|
9
|
+
module Hokusai
|
10
|
+
module Automation
|
11
|
+
class App
|
12
|
+
attr_reader :driver
|
13
|
+
|
14
|
+
def self.queue
|
15
|
+
@queue ||= {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(driver)
|
19
|
+
@driver = driver
|
20
|
+
end
|
21
|
+
|
22
|
+
ROUTES = [
|
23
|
+
["/commands/locate", DriverCommands::Locate],
|
24
|
+
["/commands/invoke", DriverCommands::Invoke],
|
25
|
+
["/commands/attribute", DriverCommands::GetAttribute],
|
26
|
+
["/commands/click", DriverCommands::TriggerMouseClick],
|
27
|
+
["/commands/drag", DriverCommands::TriggerMouseDrag],
|
28
|
+
["/commands/hover", DriverCommands::TriggerMouseHover],
|
29
|
+
["/commands/mousemove", DriverCommands::TriggerMouseMove],
|
30
|
+
["/commands/mousewheel", DriverCommands::TriggerMouseWheel],
|
31
|
+
["/commands/keyboard", DriverCommands::TriggerKeyboard]
|
32
|
+
].to_h
|
33
|
+
|
34
|
+
def call(env)
|
35
|
+
request = Rack::Request.new(env)
|
36
|
+
|
37
|
+
unless request.post?
|
38
|
+
return respond(404, "Not Found", {})
|
39
|
+
end
|
40
|
+
|
41
|
+
return respond(200, "") if request.path == "/ready"
|
42
|
+
|
43
|
+
if command_klass = ROUTES[request.path]
|
44
|
+
json = JSON.parse(request.body.string, symbolize_names: true)
|
45
|
+
command = command_klass.new(json)
|
46
|
+
driver.execute(command)
|
47
|
+
|
48
|
+
Log.debug { "Pushed #{command.class} command #{driver.queue.commands}" }
|
49
|
+
|
50
|
+
poll(command.request_id)
|
51
|
+
else
|
52
|
+
respond(403, "Bad Request", {})
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def poll(request_id)
|
57
|
+
poll_timeout = 2
|
58
|
+
poll_interval = 0.02
|
59
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
60
|
+
|
61
|
+
while (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) < poll_timeout
|
62
|
+
begin
|
63
|
+
if payload = driver.results[request_id]
|
64
|
+
driver.results.delete(request_id)
|
65
|
+
|
66
|
+
_, value = payload
|
67
|
+
|
68
|
+
Log.debug { "request id found! sending payload #{value}" }
|
69
|
+
|
70
|
+
if value.is_a?(Automation::Error)
|
71
|
+
message = value.message || "Something went wrong"
|
72
|
+
|
73
|
+
return respond(500, "Error occurred: #{message}" , {"Content-Type" => "text/plain"})
|
74
|
+
else
|
75
|
+
return respond(200, {"value" => value}.to_json)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
sleep poll_interval
|
80
|
+
rescue ex
|
81
|
+
respond(500, "Error occurred while processing command: #{ex.message}", {"Content-Type" => "text/plain"})
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
respond(408, "Timeout", {"Content-Type" => "text/plain"})
|
86
|
+
end
|
87
|
+
|
88
|
+
def parse_body(request)
|
89
|
+
JSON.parse(request.body, symbolize_names: true) unless request.body.nil?
|
90
|
+
end
|
91
|
+
|
92
|
+
def respond(status, message, headers = {"Content-Type" => "application/json"})
|
93
|
+
[status, headers, message]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class Server
|
98
|
+
def self.start(*args, driver: Hokusai::Automation::Driver.new)
|
99
|
+
app = App.new(driver)
|
100
|
+
|
101
|
+
@socket = Thin::Server.new(*args, app)
|
102
|
+
Hokusai::ThreadPool.post do
|
103
|
+
@socket.start
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.stop
|
108
|
+
@socket.stop
|
109
|
+
|
110
|
+
Hokusai::ThreadPool.prune_pool
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Hokusai::Backends
|
2
|
+
class RaylibBackend::ConfigError < StandardError; end
|
3
|
+
|
4
|
+
class RaylibBackend::Config
|
5
|
+
attr_accessor :width, :height, :fps,
|
6
|
+
:title, :config_flags, :window_state_flags,
|
7
|
+
:automation_driver, :background, :after_load_cb,
|
8
|
+
:host, :port, :automated, :on_reload, :event_waiting
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@width = 500
|
12
|
+
@height = 500
|
13
|
+
@fps = 60
|
14
|
+
@title = "(Unknown Title)"
|
15
|
+
@config_flags = Raylib::FLAG_WINDOW_RESIZABLE | Raylib::FLAG_VSYNC_HINT
|
16
|
+
@window_state_flags = Raylib::FLAG_WINDOW_RESIZABLE
|
17
|
+
@automation_driver = nil
|
18
|
+
@background = Raylib::WHITE
|
19
|
+
@after_load_cb = nil
|
20
|
+
@host = "127.0.0.1"
|
21
|
+
@port = 4333
|
22
|
+
@automated = false
|
23
|
+
@on_reload = ->(_){}
|
24
|
+
@event_waiting = false
|
25
|
+
end
|
26
|
+
|
27
|
+
def start_automation_driver
|
28
|
+
raise ConfigError.new("Need a Hokusai::Driver in order to automate") if automation_driver.nil?
|
29
|
+
|
30
|
+
automation_driver.serve(host, port)
|
31
|
+
end
|
32
|
+
|
33
|
+
def automate(host, port)
|
34
|
+
self.host = host
|
35
|
+
self.port = port
|
36
|
+
self.automated = true
|
37
|
+
end
|
38
|
+
|
39
|
+
def after_load(&block)
|
40
|
+
self.after_load_cb = block
|
41
|
+
end
|
42
|
+
|
43
|
+
def on_reload(&block)
|
44
|
+
@on_reload = block
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Hokusai
|
2
|
+
module Backends
|
3
|
+
class RaylibBackend
|
4
|
+
class DataForCb < FFI::Struct
|
5
|
+
layout :size, :int,
|
6
|
+
:spacing, :int,
|
7
|
+
:raw, :pointer
|
8
|
+
|
9
|
+
def self.create(size, spacing, raw)
|
10
|
+
obj = new.tap do |instance|
|
11
|
+
instance[:size] = size
|
12
|
+
instance[:spacing] = spacing
|
13
|
+
instance[:raw] = raw
|
14
|
+
end
|
15
|
+
|
16
|
+
yield obj.to_ptr
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
OnWidthCb = Proc.new do |char, ffi_pointer|
|
21
|
+
data = DataForCb.new ffi_pointer
|
22
|
+
|
23
|
+
Raylib.MeasureTextEx(data[:raw], "#{char.chr}", data[:size], data[:spacing]).x + data[:spacing]
|
24
|
+
end
|
25
|
+
|
26
|
+
class Font < Hokusai::Font
|
27
|
+
attr_reader :raw
|
28
|
+
|
29
|
+
DEFAULT = "–—‘’“”…\r\n\t0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%%^&*(),.?/\"\\[]-_=+|~`{}<>;:'\0"
|
30
|
+
|
31
|
+
def self.default
|
32
|
+
font = Raylib.GetFontDefault
|
33
|
+
Raylib.SetTextureFilter(font.texture, Raylib::TEXTURE_FILTER_BILINEAR)
|
34
|
+
Raylib.GenTextureMipmaps(font.texture)
|
35
|
+
|
36
|
+
new(font)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.from(file)
|
40
|
+
font = Raylib.LoadFont(file)
|
41
|
+
Raylib.SetTextureFilter(font.texture, Raylib::TEXTURE_FILTER_BILINEAR)
|
42
|
+
Raylib.GenTextureMipmaps(font.texture)
|
43
|
+
|
44
|
+
new(font)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.from_ext(file, font_size, codepoint_string = DEFAULT)
|
48
|
+
ptr = FFI::MemoryPointer.new :int
|
49
|
+
codepoints = Raylib.LoadCodepoints(codepoint_string, ptr)
|
50
|
+
count = ptr.read_int
|
51
|
+
|
52
|
+
raylib_font = Raylib.LoadFontEx(file, font_size, codepoints, count)
|
53
|
+
Raylib.GenTextureMipmaps(raylib_font.texture)
|
54
|
+
Raylib.SetTextureFilter(raylib_font.texture, Raylib::TEXTURE_FILTER_BILINEAR)
|
55
|
+
|
56
|
+
font = new(raylib_font)
|
57
|
+
Raylib.UnloadCodepoints(codepoints)
|
58
|
+
|
59
|
+
font
|
60
|
+
end
|
61
|
+
|
62
|
+
def initialize(raw, spacing = 1.0)
|
63
|
+
@raw = raw
|
64
|
+
@spacing = spacing
|
65
|
+
end
|
66
|
+
|
67
|
+
# returns the spacing for this font
|
68
|
+
# based on the text size
|
69
|
+
def spacing
|
70
|
+
ssize = raw.baseSize || 1
|
71
|
+
ssize = 10 if ssize < 10
|
72
|
+
|
73
|
+
(ssize / (raw.baseSize.zero? ? 1 : raw.baseSize)).to_f
|
74
|
+
end
|
75
|
+
|
76
|
+
def measure(string, size)
|
77
|
+
vec = Raylib.MeasureTextEx(raw, string, size, spacing)
|
78
|
+
|
79
|
+
[vec.x, vec.y]
|
80
|
+
end
|
81
|
+
|
82
|
+
def height
|
83
|
+
raw.baseSize
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def clamp_markdown(text, size, width, initial_offset = 0.0)
|
88
|
+
clamping_pointer = FFI::MemoryPointer.new :pointer
|
89
|
+
RaylibBackend::DataForCb.create(size, spacing, raw) do |ptr|
|
90
|
+
ret = LibHokusai.hoku_text_md_clamp(clamping_pointer, text, width, initial_offset, ptr, RaylibBackend::OnWidthCb)
|
91
|
+
raise Hokusai::Error.new("Clamping failed") unless ret.zero?
|
92
|
+
end
|
93
|
+
|
94
|
+
clamping = LibHokusai::HokuClamping.new(FFI::AutoPointer.new(clamping_pointer.get_pointer(0), LibHokusai.method(:hoku_text_clamping_free)))
|
95
|
+
|
96
|
+
Hokusai::Clamping.new(clamping, markdown: true)
|
97
|
+
end
|
98
|
+
|
99
|
+
def clamp(text, size, width, initial_offset = 0.0)
|
100
|
+
clamping_pointer = FFI::MemoryPointer.new :pointer
|
101
|
+
RaylibBackend::DataForCb.create(size, spacing, raw) do |ptr|
|
102
|
+
ret = LibHokusai.hoku_text_clamp(clamping_pointer, text, width, initial_offset, ptr, RaylibBackend::OnWidthCb)
|
103
|
+
raise Hokusai::Error.new("Clamping failed") unless ret.zero?
|
104
|
+
end
|
105
|
+
|
106
|
+
clamping = LibHokusai::HokuClamping.new(FFI::AutoPointer.new(clamping_pointer.get_pointer(0), LibHokusai.method(:hoku_text_clamping_free)))
|
107
|
+
|
108
|
+
Hokusai::Clamping.new(clamping)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Hokusai::Backends
|
2
|
+
class RaylibBackend
|
3
|
+
Keys = [
|
4
|
+
[:null, Raylib::KEY_NULL],
|
5
|
+
[:left_shift, Raylib::KEY_LEFT_SHIFT],
|
6
|
+
[:left_control, Raylib::KEY_LEFT_CONTROL],
|
7
|
+
[:left_alt, Raylib::KEY_LEFT_ALT],
|
8
|
+
[:left_super, Raylib::KEY_LEFT_SUPER],
|
9
|
+
[:right_shift, Raylib::KEY_RIGHT_SHIFT],
|
10
|
+
[:right_control, Raylib::KEY_RIGHT_CONTROL],
|
11
|
+
[:right_alt, Raylib::KEY_RIGHT_ALT],
|
12
|
+
[:right_super, Raylib::KEY_RIGHT_SUPER],
|
13
|
+
[:apostrophe, Raylib::KEY_APOSTROPHE],
|
14
|
+
[:comma, Raylib::KEY_COMMA],
|
15
|
+
[:minus, Raylib::KEY_MINUS],
|
16
|
+
[:period, Raylib::KEY_PERIOD],
|
17
|
+
[:slash, Raylib::KEY_SLASH],
|
18
|
+
[:zero, Raylib::KEY_ZERO],
|
19
|
+
[:one, Raylib::KEY_ONE],
|
20
|
+
[:two, Raylib::KEY_TWO],
|
21
|
+
[:three, Raylib::KEY_THREE],
|
22
|
+
[:four, Raylib::KEY_FOUR],
|
23
|
+
[:five, Raylib::KEY_FIVE],
|
24
|
+
[:six, Raylib::KEY_SIX],
|
25
|
+
[:seven, Raylib::KEY_SEVEN],
|
26
|
+
[:eight, Raylib::KEY_EIGHT],
|
27
|
+
[:nine, Raylib::KEY_NINE],
|
28
|
+
[:semicolon, Raylib::KEY_SEMICOLON],
|
29
|
+
[:equal, Raylib::KEY_EQUAL],
|
30
|
+
[:a, Raylib::KEY_A],
|
31
|
+
[:b, Raylib::KEY_B],
|
32
|
+
[:c, Raylib::KEY_C],
|
33
|
+
[:d, Raylib::KEY_D],
|
34
|
+
[:e, Raylib::KEY_E],
|
35
|
+
[:f, Raylib::KEY_F],
|
36
|
+
[:g, Raylib::KEY_G],
|
37
|
+
[:h, Raylib::KEY_H],
|
38
|
+
[:i, Raylib::KEY_I],
|
39
|
+
[:j, Raylib::KEY_J],
|
40
|
+
[:k, Raylib::KEY_K],
|
41
|
+
[:l, Raylib::KEY_L],
|
42
|
+
[:m, Raylib::KEY_M],
|
43
|
+
[:n, Raylib::KEY_N],
|
44
|
+
[:o, Raylib::KEY_O],
|
45
|
+
[:p, Raylib::KEY_P],
|
46
|
+
[:q, Raylib::KEY_Q],
|
47
|
+
[:r, Raylib::KEY_R],
|
48
|
+
[:s, Raylib::KEY_S],
|
49
|
+
[:t, Raylib::KEY_T],
|
50
|
+
[:u, Raylib::KEY_U],
|
51
|
+
[:v, Raylib::KEY_V],
|
52
|
+
[:w, Raylib::KEY_W],
|
53
|
+
[:x, Raylib::KEY_X],
|
54
|
+
[:y, Raylib::KEY_Y],
|
55
|
+
[:z, Raylib::KEY_Z],
|
56
|
+
[:left_bracket, Raylib::KEY_LEFT_BRACKET],
|
57
|
+
[:backslash, Raylib::KEY_BACKSLASH],
|
58
|
+
[:right_bracket, Raylib::KEY_RIGHT_BRACKET],
|
59
|
+
[:grave, Raylib::KEY_GRAVE],
|
60
|
+
[:space, Raylib::KEY_SPACE],
|
61
|
+
[:escape, Raylib::KEY_ESCAPE],
|
62
|
+
[:enter, Raylib::KEY_ENTER],
|
63
|
+
[:tab, Raylib::KEY_TAB],
|
64
|
+
[:backspace, Raylib::KEY_BACKSPACE],
|
65
|
+
[:insert, Raylib::KEY_INSERT],
|
66
|
+
[:delete, Raylib::KEY_DELETE],
|
67
|
+
[:right, Raylib::KEY_RIGHT],
|
68
|
+
[:left, Raylib::KEY_LEFT],
|
69
|
+
[:down, Raylib::KEY_DOWN],
|
70
|
+
[:up, Raylib::KEY_UP],
|
71
|
+
[:page_up, Raylib::KEY_PAGE_UP],
|
72
|
+
[:page_down, Raylib::KEY_PAGE_DOWN],
|
73
|
+
[:home, Raylib::KEY_HOME],
|
74
|
+
[:end, Raylib::KEY_END],
|
75
|
+
[:caps_lock, Raylib::KEY_CAPS_LOCK],
|
76
|
+
[:scroll_lock, Raylib::KEY_SCROLL_LOCK],
|
77
|
+
[:num_lock, Raylib::KEY_NUM_LOCK],
|
78
|
+
[:print_screen, Raylib::KEY_PRINT_SCREEN],
|
79
|
+
[:pause, Raylib::KEY_PAUSE],
|
80
|
+
[:f1, Raylib::KEY_F1],
|
81
|
+
[:f2, Raylib::KEY_F2],
|
82
|
+
[:f3, Raylib::KEY_F3],
|
83
|
+
[:f4, Raylib::KEY_F4],
|
84
|
+
[:f5, Raylib::KEY_F5],
|
85
|
+
[:f6, Raylib::KEY_F6],
|
86
|
+
[:f7, Raylib::KEY_F7],
|
87
|
+
[:f8, Raylib::KEY_F8],
|
88
|
+
[:f9, Raylib::KEY_F9],
|
89
|
+
[:f10, Raylib::KEY_F10],
|
90
|
+
[:f11, Raylib::KEY_F11],
|
91
|
+
[:f12, Raylib::KEY_F12],
|
92
|
+
[:left_shift, Raylib::KEY_LEFT_SHIFT],
|
93
|
+
[:left_control, Raylib::KEY_LEFT_CONTROL],
|
94
|
+
[:left_alt, Raylib::KEY_LEFT_ALT],
|
95
|
+
[:left_super, Raylib::KEY_LEFT_SUPER],
|
96
|
+
[:right_shift, Raylib::KEY_RIGHT_SHIFT],
|
97
|
+
[:right_control, Raylib::KEY_RIGHT_CONTROL],
|
98
|
+
[:right_alt, Raylib::KEY_RIGHT_ALT],
|
99
|
+
[:right_super, Raylib::KEY_RIGHT_SUPER],
|
100
|
+
[:kb_menu, Raylib::KEY_KB_MENU],
|
101
|
+
[:kp_0, Raylib::KEY_KP_0],
|
102
|
+
[:kp_1, Raylib::KEY_KP_1],
|
103
|
+
[:kp_2, Raylib::KEY_KP_2],
|
104
|
+
[:kp_3, Raylib::KEY_KP_3],
|
105
|
+
[:kp_4, Raylib::KEY_KP_4],
|
106
|
+
[:kp_5, Raylib::KEY_KP_5],
|
107
|
+
[:kp_6, Raylib::KEY_KP_6],
|
108
|
+
[:kp_7, Raylib::KEY_KP_7],
|
109
|
+
[:kp_8, Raylib::KEY_KP_8],
|
110
|
+
[:kp_9, Raylib::KEY_KP_9],
|
111
|
+
[:kp_decimal, Raylib::KEY_KP_DECIMAL],
|
112
|
+
[:kp_divide, Raylib::KEY_KP_DIVIDE],
|
113
|
+
[:kp_multiply, Raylib::KEY_KP_MULTIPLY],
|
114
|
+
[:kp_subtract, Raylib::KEY_KP_SUBTRACT],
|
115
|
+
[:kp_add, Raylib::KEY_KP_ADD],
|
116
|
+
[:kp_enter, Raylib::KEY_KP_ENTER],
|
117
|
+
[:kp_equal, Raylib::KEY_KP_EQUAL],
|
118
|
+
[:back, Raylib::KEY_BACK],
|
119
|
+
[:menu, Raylib::KEY_MENU],
|
120
|
+
[:volume_up, Raylib::KEY_VOLUME_UP],
|
121
|
+
[:volume_down, Raylib::KEY_VOLUME_DOWN]]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|