zaniah 0.1.0

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 (166) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +70 -0
  5. data/assets/fonts/Abel-Regular.ttf +0 -0
  6. data/assets/fonts/OFL.txt +93 -0
  7. data/docs/adr/000-template.md +24 -0
  8. data/docs/adr/001-native-gpu-backends.md +36 -0
  9. data/docs/adr/002-objective-c-aggregates.md +34 -0
  10. data/docs/adr/003-fiddle-call-boundary.md +33 -0
  11. data/docs/adr/README.md +10 -0
  12. data/docs/native.md +66 -0
  13. data/docs/process_pool.md +67 -0
  14. data/docs/text.md +90 -0
  15. data/docs/vector_and_list.md +52 -0
  16. data/examples/ffi_bench.rb +16 -0
  17. data/examples/linux_smoke.rb +53 -0
  18. data/examples/mac_event_check.rb +61 -0
  19. data/examples/mac_poll_bench.rb +24 -0
  20. data/examples/metal_state_check.rb +72 -0
  21. data/examples/native_bench.rb +18 -0
  22. data/examples/native_drop.rb +82 -0
  23. data/examples/native_font.rb +15 -0
  24. data/examples/native_ime.rb +50 -0
  25. data/examples/native_smoke.rb +75 -0
  26. data/examples/native_text_bench.rb +83 -0
  27. data/examples/native_watch.rb +25 -0
  28. data/examples/vulkan_triangle.rb +20 -0
  29. data/examples/word_count_worker.rb +8 -0
  30. data/lib/zaniah/anchored.rb +10 -0
  31. data/lib/zaniah/app.rb +130 -0
  32. data/lib/zaniah/bounds.rb +22 -0
  33. data/lib/zaniah/canvas.rb +15 -0
  34. data/lib/zaniah/color.rb +35 -0
  35. data/lib/zaniah/configuration.rb +5 -0
  36. data/lib/zaniah/corners.rb +7 -0
  37. data/lib/zaniah/data_compat.rb +25 -0
  38. data/lib/zaniah/device_pixels.rb +7 -0
  39. data/lib/zaniah/div.rb +5 -0
  40. data/lib/zaniah/edges.rb +7 -0
  41. data/lib/zaniah/element.rb +106 -0
  42. data/lib/zaniah/entity.rb +9 -0
  43. data/lib/zaniah/entity_context.rb +17 -0
  44. data/lib/zaniah/error.rb +5 -0
  45. data/lib/zaniah/ffi/com.rb +24 -0
  46. data/lib/zaniah/ffi/library.rb +29 -0
  47. data/lib/zaniah/ffi/objc.rb +86 -0
  48. data/lib/zaniah/ffi/struct/signature.rb +46 -0
  49. data/lib/zaniah/ffi/struct.rb +61 -0
  50. data/lib/zaniah/ffi/wayland.rb +140 -0
  51. data/lib/zaniah/frame_context.rb +14 -0
  52. data/lib/zaniah/geometry.rb +16 -0
  53. data/lib/zaniah/gpu/buffer.rb +23 -0
  54. data/lib/zaniah/gpu/frame_encoder.rb +43 -0
  55. data/lib/zaniah/gpu/instance_packing.rb +53 -0
  56. data/lib/zaniah/gpu/metal.rb +209 -0
  57. data/lib/zaniah/gpu/open_gl.rb +210 -0
  58. data/lib/zaniah/gpu/pipeline.rb +7 -0
  59. data/lib/zaniah/gpu/software.rb +126 -0
  60. data/lib/zaniah/gpu/texture.rb +33 -0
  61. data/lib/zaniah/gpu/vulkan.rb +233 -0
  62. data/lib/zaniah/gpu.rb +18 -0
  63. data/lib/zaniah/hsla.rb +14 -0
  64. data/lib/zaniah/image.rb +19 -0
  65. data/lib/zaniah/input/action_registry.rb +12 -0
  66. data/lib/zaniah/input/composition.rb +7 -0
  67. data/lib/zaniah/input/context_predicate.rb +87 -0
  68. data/lib/zaniah/input/dispatcher.rb +59 -0
  69. data/lib/zaniah/input/file_drop.rb +7 -0
  70. data/lib/zaniah/input/focus_handle.rb +24 -0
  71. data/lib/zaniah/input/key_down.rb +7 -0
  72. data/lib/zaniah/input/key_up.rb +7 -0
  73. data/lib/zaniah/input/keymap/binding.rb +9 -0
  74. data/lib/zaniah/input/keymap.rb +55 -0
  75. data/lib/zaniah/input/keystroke.rb +20 -0
  76. data/lib/zaniah/input/mouse_down.rb +7 -0
  77. data/lib/zaniah/input/mouse_move.rb +7 -0
  78. data/lib/zaniah/input/mouse_up.rb +7 -0
  79. data/lib/zaniah/input/scroll_wheel.rb +7 -0
  80. data/lib/zaniah/input/text_input.rb +7 -0
  81. data/lib/zaniah/input.rb +17 -0
  82. data/lib/zaniah/layout/available_space.rb +11 -0
  83. data/lib/zaniah/layout/engine.rb +214 -0
  84. data/lib/zaniah/layout/node.rb +36 -0
  85. data/lib/zaniah/layout/style.rb +19 -0
  86. data/lib/zaniah/layout/tree.rb +16 -0
  87. data/lib/zaniah/layout.rb +11 -0
  88. data/lib/zaniah/length.rb +14 -0
  89. data/lib/zaniah/length_units.rb +9 -0
  90. data/lib/zaniah/list/height_index.rb +68 -0
  91. data/lib/zaniah/list.rb +101 -0
  92. data/lib/zaniah/overlay.rb +10 -0
  93. data/lib/zaniah/platform/display.rb +7 -0
  94. data/lib/zaniah/platform/file_event.rb +7 -0
  95. data/lib/zaniah/platform/headless/window.rb +185 -0
  96. data/lib/zaniah/platform/linux/appearance_aware.rb +60 -0
  97. data/lib/zaniah/platform/linux/displays.rb +55 -0
  98. data/lib/zaniah/platform/linux/free_type.rb +80 -0
  99. data/lib/zaniah/platform/linux/watcher.rb +70 -0
  100. data/lib/zaniah/platform/linux/wayland_display_discovery.rb +60 -0
  101. data/lib/zaniah/platform/linux/wayland_window.rb +369 -0
  102. data/lib/zaniah/platform/linux/window.rb +418 -0
  103. data/lib/zaniah/platform/linux.rb +3 -0
  104. data/lib/zaniah/platform/mac/app.rb +67 -0
  105. data/lib/zaniah/platform/mac/core_text.rb +94 -0
  106. data/lib/zaniah/platform/mac/displays.rb +23 -0
  107. data/lib/zaniah/platform/mac/watcher.rb +63 -0
  108. data/lib/zaniah/platform/mac/window.rb +298 -0
  109. data/lib/zaniah/platform/mac.rb +19 -0
  110. data/lib/zaniah/platform/tui/input_decoder.rb +145 -0
  111. data/lib/zaniah/platform/tui/text_renderer.rb +40 -0
  112. data/lib/zaniah/platform/tui/window.rb +91 -0
  113. data/lib/zaniah/platform/windows/terminal.rb +127 -0
  114. data/lib/zaniah/platform/windows/watcher.rb +91 -0
  115. data/lib/zaniah/platform/windows/window.rb +407 -0
  116. data/lib/zaniah/platform/windows.rb +3 -0
  117. data/lib/zaniah/platform.rb +34 -0
  118. data/lib/zaniah/png.rb +118 -0
  119. data/lib/zaniah/point.rb +8 -0
  120. data/lib/zaniah/process_pool/worker.rb +7 -0
  121. data/lib/zaniah/process_pool.rb +239 -0
  122. data/lib/zaniah/process_wire.rb +127 -0
  123. data/lib/zaniah/quad_packer.rb +15 -0
  124. data/lib/zaniah/scene/sprite_batch.rb +7 -0
  125. data/lib/zaniah/scene.rb +167 -0
  126. data/lib/zaniah/scene_renderer.rb +8 -0
  127. data/lib/zaniah/size.rb +5 -0
  128. data/lib/zaniah/subscription.rb +14 -0
  129. data/lib/zaniah/svg/path.rb +134 -0
  130. data/lib/zaniah/svg/rasterizable.rb +186 -0
  131. data/lib/zaniah/svg.rb +295 -0
  132. data/lib/zaniah/task/cancelled.rb +7 -0
  133. data/lib/zaniah/task/timeout.rb +7 -0
  134. data/lib/zaniah/task.rb +51 -0
  135. data/lib/zaniah/task_executor.rb +105 -0
  136. data/lib/zaniah/text.rb +24 -0
  137. data/lib/zaniah/text_system/atlas/entry.rb +9 -0
  138. data/lib/zaniah/text_system/atlas.rb +102 -0
  139. data/lib/zaniah/text_system/atlas_cache.rb +146 -0
  140. data/lib/zaniah/text_system/font_db/face.rb +9 -0
  141. data/lib/zaniah/text_system/font_db.rb +193 -0
  142. data/lib/zaniah/text_system/glyph.rb +7 -0
  143. data/lib/zaniah/text_system/line_layout.rb +20 -0
  144. data/lib/zaniah/text_system/renderer.rb +196 -0
  145. data/lib/zaniah/text_system/shaper.rb +430 -0
  146. data/lib/zaniah/text_system/typesetter/copy_error.rb +9 -0
  147. data/lib/zaniah/text_system/typesetter.rb +168 -0
  148. data/lib/zaniah/text_system.rb +9 -0
  149. data/lib/zaniah/unicode.rb +13 -0
  150. data/lib/zaniah/uniform_list.rb +30 -0
  151. data/lib/zaniah/version.rb +5 -0
  152. data/lib/zaniah/view.rb +13 -0
  153. data/lib/zaniah.rb +29 -0
  154. data/sig/app.rbs +80 -0
  155. data/sig/elements.rbs +129 -0
  156. data/sig/gpu.rbs +108 -0
  157. data/sig/input.rbs +114 -0
  158. data/sig/layout.rbs +53 -0
  159. data/sig/native.rbs +88 -0
  160. data/sig/platform.rbs +94 -0
  161. data/sig/scene.rbs +52 -0
  162. data/sig/shaper.rbs +8 -0
  163. data/sig/text.rbs +137 -0
  164. data/sig/zaniah.rbs +120 -0
  165. data/tools/check_dependencies.rb +52 -0
  166. metadata +249 -0
data/sig/input.rbs ADDED
@@ -0,0 +1,114 @@
1
+ module Zaniah
2
+ module Input
3
+ type modifiers = Array[String]
4
+ type button = :left | :middle | :right | Integer
5
+ type context = Hash[String | Symbol, String | Symbol | Numeric | bool | nil]
6
+ type action = String | Symbol | Hash[String, untyped] | Array[untyped]
7
+ type event = KeyDown | KeyUp | TextInput | Composition | mouse_event | FileDrop
8
+ type mouse_event = MouseDown | MouseUp | MouseMove | ScrollWheel
9
+
10
+ class KeyDown < Data
11
+ attr_reader keystroke: String
12
+ attr_reader is_held: bool
13
+ def self.new: (String keystroke, bool is_held) -> KeyDown
14
+ | (keystroke: String, is_held: bool) -> KeyDown
15
+ end
16
+ class KeyUp < Data
17
+ attr_reader keystroke: String
18
+ def self.new: (String keystroke) -> KeyUp
19
+ | (keystroke: String) -> KeyUp
20
+ end
21
+ class TextInput < Data
22
+ attr_reader text: String
23
+ def self.new: (String text) -> TextInput
24
+ | (text: String) -> TextInput
25
+ end
26
+ class MouseDown < Data
27
+ attr_reader position: Point
28
+ attr_reader button: button
29
+ attr_reader modifiers: modifiers
30
+ attr_reader click_count: Integer
31
+ def self.new: (Point position, button button, modifiers modifiers, Integer click_count) -> MouseDown
32
+ | (position: Point, button: button, modifiers: modifiers, click_count: Integer) -> MouseDown
33
+ end
34
+ class MouseUp < Data
35
+ attr_reader position: Point
36
+ attr_reader button: button
37
+ attr_reader modifiers: modifiers
38
+ def self.new: (Point position, button button, modifiers modifiers) -> MouseUp
39
+ | (position: Point, button: button, modifiers: modifiers) -> MouseUp
40
+ end
41
+ class MouseMove < Data
42
+ attr_reader position: Point
43
+ attr_reader modifiers: modifiers
44
+ def self.new: (Point position, modifiers modifiers) -> MouseMove
45
+ | (position: Point, modifiers: modifiers) -> MouseMove
46
+ end
47
+ class ScrollWheel < Data
48
+ attr_reader position: Point
49
+ attr_reader delta: Point
50
+ attr_reader phase: Symbol
51
+ attr_reader modifiers: modifiers
52
+ def self.new: (Point position, Point delta, Symbol phase, modifiers modifiers) -> ScrollWheel
53
+ | (position: Point, delta: Point, phase: Symbol, modifiers: modifiers) -> ScrollWheel
54
+ end
55
+ class Composition < Data
56
+ attr_reader text: String
57
+ attr_reader selection: [Integer, Integer]
58
+ def self.new: (String text, [Integer, Integer] selection) -> Composition
59
+ | (text: String, selection: [Integer, Integer]) -> Composition
60
+ end
61
+ class FileDrop < Data
62
+ attr_reader paths: Array[String]
63
+ attr_reader position: Point
64
+ def self.new: (Array[String] paths, Point position) -> FileDrop
65
+ | (paths: Array[String], position: Point) -> FileDrop
66
+ end
67
+ module Keystroke
68
+ def self.normalize: (String value) -> String
69
+ end
70
+ class ContextPredicate
71
+ def initialize: (String? source) -> void
72
+ def call: (context values) -> bool
73
+ end
74
+ class Keymap
75
+ class Binding < Data
76
+ attr_reader keys: Array[String]
77
+ attr_reader predicate: ContextPredicate
78
+ attr_reader action: action
79
+ def self.new: (Array[String] keys, ContextPredicate predicate, action action) -> Binding
80
+ | (keys: Array[String], predicate: ContextPredicate, action: action) -> Binding
81
+ end
82
+ def initialize: (?timeout: Numeric) -> void
83
+ def bind: (String keys, action action, ?context: String) -> self
84
+ def load_json: (String text) -> self
85
+ def dispatch: (String key, ?context: context, ?now: Numeric) -> (action | :pending | nil)
86
+ def bindings: () -> Array[Binding]
87
+ end
88
+ class FocusHandle
89
+ attr_reader parent: FocusHandle?
90
+ attr_reader children: Array[FocusHandle]
91
+ attr_reader context: context
92
+ attr_accessor on_action: (^(action) -> bool)?
93
+ attr_accessor on_focus: (^(bool) -> void)?
94
+ def initialize: (?parent: FocusHandle?, ?context: context) -> void
95
+ def ancestors: () -> Array[FocusHandle]
96
+ end
97
+ class Dispatcher
98
+ attr_reader focused: FocusHandle?
99
+ def initialize: (?keymap: Keymap) -> void
100
+ def focus: (FocusHandle? handle) -> void
101
+ def key: (String key) -> (action | :pending | nil)
102
+ def clear_hits: () -> void
103
+ def hit: (Bounds bounds, ?clip: Bounds?) { (mouse_event | FileDrop) -> (bool | :capture | nil) } -> void
104
+ def clip: [T] (Bounds bounds) { () -> T } -> T
105
+ def mouse: (mouse_event | FileDrop event) -> bool
106
+ end
107
+ class ActionRegistry
108
+ def initialize: () -> void
109
+ def register: (String | Symbol name, ?description: String | Symbol) { (*untyped) -> untyped } -> void
110
+ def call: (String | Symbol name, *untyped args) -> untyped
111
+ def entries: () -> Hash[String, String | Symbol]
112
+ end
113
+ end
114
+ end
data/sig/layout.rbs ADDED
@@ -0,0 +1,53 @@
1
+ module Zaniah
2
+ module Layout
3
+ type style_value = dimension | Edges | Array[dimension] | Symbol | bool | nil
4
+ type properties = Hash[Symbol, style_value]
5
+ type measurement = [Numeric, Numeric] | [Numeric, Numeric, Numeric]
6
+ type measure = ^(Numeric width, Numeric height) -> measurement
7
+
8
+ class AvailableSpace < Data
9
+ attr_reader kind: :definite | :min_content | :max_content
10
+ attr_reader value: Numeric?
11
+ def self.new: (:definite | :min_content | :max_content kind, Numeric? value) -> AvailableSpace
12
+ | (kind: :definite | :min_content | :max_content, value: Numeric?) -> AvailableSpace
13
+ def self.definite: (Numeric value) -> AvailableSpace
14
+ def self.min_content: () -> AvailableSpace
15
+ def self.max_content: () -> AvailableSpace
16
+ end
17
+ class Style
18
+ DEFAULTS: properties
19
+ def initialize: (**style_value properties) -> void
20
+ def []: (Symbol name) -> style_value
21
+ def merge: (**style_value properties) -> Style
22
+ def to_h: () -> properties
23
+ end
24
+ class Node
25
+ attr_reader style: Style
26
+ attr_reader children: Array[Node]
27
+ attr_reader generation: Integer
28
+ attr_accessor bounds: Bounds
29
+ attr_accessor parent: Node?
30
+ attr_accessor measure: measure?
31
+ attr_accessor baseline: Numeric
32
+ def initialize: (?style: Style | properties, ?children: Array[Node], ?measure: measure?) -> void
33
+ def add: (Node child) -> Node
34
+ def style=: (Style | properties style) -> void
35
+ def touch: () -> void
36
+ end
37
+ class Engine
38
+ def initialize: (?rem: Numeric) -> void
39
+ def compute: (Node root, width: Numeric, height: Numeric, ?x: Numeric, ?y: Numeric) -> Bounds
40
+ def measure: (Node node, width: Numeric, height: Numeric) -> [Numeric, Numeric]
41
+ end
42
+ class Tree
43
+ attr_reader nodes: Array[Node]
44
+ def initialize: () -> void
45
+ def new_node: (?style: Style | properties, ?children: Array[Node], ?measure: measure?) -> Integer
46
+ def add_child: (Integer parent, Integer child) -> Node
47
+ def set_style: (Integer id, **style_value style) -> Style
48
+ def compute: (Integer id, width: Numeric, height: Numeric) -> Bounds
49
+ def bounds: (Integer id) -> Bounds
50
+ end
51
+ end
52
+ class LayoutTree = Layout::Tree
53
+ end
data/sig/native.rbs ADDED
@@ -0,0 +1,88 @@
1
+ module Zaniah
2
+ module Platform
3
+ module Mac
4
+ class Window < Headless::Window
5
+ attr_reader handle: Integer
6
+ attr_reader view: Integer
7
+ attr_reader layer: Integer?
8
+ def initialize: (?gpu: :metal | :opengl | :gl, ?width: Numeric, ?height: Numeric, ?title: String, ?scale_factor: Numeric) -> void
9
+ def create_device: (:metal | :opengl | :gl backend) -> GPU::_Device
10
+ def tick: (?poll_events: bool) -> void
11
+ def run: () -> void
12
+ def clipboard: () -> String
13
+ def clipboard=: (String text) -> void
14
+ def clipboard_paths: () -> Array[String]
15
+ def appearance: () -> (:light | :dark)
16
+ def on_appearance: () { (:light | :dark) -> void } -> void
17
+ def tooltip=: (String text) -> void
18
+ def prompt_for_paths: (?multiple: bool, ?directories: bool, ?save: bool) -> Array[String]
19
+ def cursor_style=: (cursor style) -> void
20
+ def open_url: (String url) -> void
21
+ def toggle_fullscreen: () -> void
22
+ end
23
+ end
24
+ module Linux
25
+ class Window < Headless::Window
26
+ attr_reader handle: Integer
27
+ def self.new: (?display_server: :auto | :x11 | :wayland, ?gpu: :opengl | :gl, ?width: Numeric, ?height: Numeric, ?title: String, ?scale_factor: Numeric) -> (Window | WaylandWindow)
28
+ def initialize: (?gpu: :opengl | :gl, ?width: Numeric, ?height: Numeric, ?title: String, ?scale_factor: Numeric) -> void
29
+ def create_device: (:opengl | :gl backend) -> GPU::OpenGL
30
+ def run: () -> void
31
+ def clipboard: () -> String?
32
+ def clipboard=: (String text) -> void
33
+ def clipboard_paths: () -> Array[String]
34
+ def appearance: () -> (:light | :dark)
35
+ def on_appearance: () { (:light | :dark) -> void } -> void
36
+ def prompt_for_paths: (?multiple: bool, ?directories: bool, ?save: bool) -> Array[String]
37
+ def cursor_style=: (cursor style) -> void
38
+ def open_url: (String url) -> bool
39
+ def toggle_fullscreen: () -> void
40
+ end
41
+ class WaylandWindow < Headless::Window
42
+ def initialize: (?gpu: :opengl | :gl, ?width: Numeric, ?height: Numeric, ?title: String, ?scale_factor: Numeric) -> void
43
+ def create_device: (:opengl | :gl backend) -> GPU::OpenGL
44
+ def run: () -> void
45
+ def clipboard: () -> String?
46
+ def clipboard=: (String text) -> void
47
+ def clipboard_paths: () -> Array[String]
48
+ def appearance: () -> (:light | :dark)
49
+ def on_appearance: () { (:light | :dark) -> void } -> void
50
+ def on_delete_surrounding: () { (Integer before, Integer after) -> void } -> void
51
+ def surrounding_text: (String text, cursor: Integer, ?anchor: Integer) -> void
52
+ def prompt_for_paths: (?multiple: bool, ?directories: bool, ?save: bool) -> Array[String]
53
+ def cursor_style=: (cursor style) -> void
54
+ def open_url: (String url) -> bool
55
+ def toggle_fullscreen: () -> void
56
+ end
57
+ end
58
+ module Windows
59
+ class Window < Headless::Window
60
+ # Opaque native pointer; only integer conversion is portable.
61
+ attr_reader handle: _ToI
62
+ def initialize: (?gpu: :opengl | :gl, ?width: Numeric, ?height: Numeric, ?title: String, ?scale_factor: Numeric) -> void
63
+ def create_device: (:opengl | :gl backend) -> GPU::OpenGL
64
+ def run: () -> void
65
+ def clipboard: () -> String?
66
+ def clipboard=: (String text) -> void
67
+ def clipboard_paths: () -> Array[String]
68
+ def appearance: () -> (:light | :dark)
69
+ def on_appearance: () { (:light | :dark) -> void } -> void
70
+ def context_menu: (menu items, ?position: Point?) -> void
71
+ def prompt_for_paths: (?multiple: bool, ?directories: bool, ?save: bool) -> Array[String]
72
+ def cursor_style=: (cursor style) -> void
73
+ def open_url: (String url) -> void
74
+ def toggle_fullscreen: () -> void
75
+ end
76
+ class Terminal
77
+ attr_reader pid: Integer
78
+ def initialize: (?command: String | Array[String] | nil, ?columns: Integer, ?rows: Integer, ?cwd: String?, ?env: Hash[String | Symbol, String | Numeric]) -> void
79
+ def self.quote_argument: (String value) -> String
80
+ def read_available: (?limit: Integer) -> String?
81
+ def write: (String bytes) -> Integer
82
+ def resize: (Integer columns, Integer rows) -> void
83
+ def alive?: () -> bool
84
+ def close: () -> void
85
+ end
86
+ end
87
+ end
88
+ end
data/sig/platform.rbs ADDED
@@ -0,0 +1,94 @@
1
+ module Zaniah
2
+ module Platform
3
+ type backend = :headless | :tui | :mac | :linux | :windows
4
+ type cursor = :arrow | :text | :pointer | :crosshair | :resize_horizontal | :resize_vertical
5
+ type text_run = [Numeric, Numeric, String, color]
6
+ type native_window = Mac::Window | Linux::Window | Linux::WaylandWindow | Windows::Window
7
+ class Display < Data
8
+ attr_reader id: Integer
9
+ attr_reader name: String
10
+ attr_reader bounds: Bounds
11
+ attr_reader scale_factor: Numeric
12
+ attr_reader primary: bool
13
+ def self.new: (Integer id, String name, Bounds bounds, Numeric scale_factor, bool primary) -> Display
14
+ | (id: Integer, name: String, bounds: Bounds, scale_factor: Numeric, primary: bool) -> Display
15
+ end
16
+ def self.displays: (?backend: backend | :auto, ?display_server: :auto | :x11 | :wayland) -> Array[Display]
17
+
18
+ def self.open_window: (?backend: :headless, ?width: Numeric, ?height: Numeric, ?title: String, ?scale_factor: Numeric) -> Headless::Window
19
+ | (backend: :tui, ?input: IO, ?output: IO, ?width: Numeric, ?height: Numeric, ?title: String, ?scale_factor: Numeric) -> TUI::Window
20
+ | (backend: :mac, ?gpu: :metal | :opengl | :gl, ?width: Numeric, ?height: Numeric, ?title: String, ?scale_factor: Numeric) -> Mac::Window
21
+ | (backend: :linux, ?display_server: :auto | :x11 | :wayland, ?gpu: :opengl | :gl, ?width: Numeric, ?height: Numeric, ?title: String, ?scale_factor: Numeric) -> (Linux::Window | Linux::WaylandWindow)
22
+ | (backend: :windows, ?gpu: :opengl | :gl, ?width: Numeric, ?height: Numeric, ?title: String, ?scale_factor: Numeric) -> Windows::Window
23
+
24
+ interface _Watcher
25
+ def poll: (?timeout: Numeric) -> Array[FileEvent]
26
+ def close: () -> void
27
+ end
28
+ class FileEvent < Data
29
+ attr_reader kind: :created | :modified | :deleted | :renamed | :overflow
30
+ attr_reader path: String?
31
+ attr_reader old_path: String?
32
+ def self.new: (:created | :modified | :deleted | :renamed | :overflow kind, String? path, String? old_path) -> FileEvent
33
+ | (kind: :created | :modified | :deleted | :renamed | :overflow, path: String?, old_path: String?) -> FileEvent
34
+ end
35
+ def self.watch: (String | Array[String] paths, ?latency: Numeric) -> _Watcher
36
+
37
+ module Headless
38
+ class Window
39
+ attr_reader content_size: Size
40
+ attr_reader scene: Scene
41
+ attr_reader device: GPU::_Device
42
+ attr_reader dispatcher: Input::Dispatcher
43
+ attr_reader scale_factor: Numeric
44
+ attr_reader text_runs: Array[text_run]
45
+ attr_accessor text_system: TextSystem::_System?
46
+ attr_accessor ime_state: Bounds?
47
+ attr_accessor title: String
48
+ def initialize: (?width: Numeric, ?height: Numeric, ?title: String, ?scale_factor: Numeric) -> void
49
+ def on_input: () { (Input::event) -> void } -> void
50
+ def on_resize: () { (Size) -> void } -> void
51
+ def on_close: () { () -> (bool | nil) } -> void
52
+ def on_moved: () { ([Numeric, Numeric]) -> void } -> void
53
+ def on_tick: () { () -> void } -> void
54
+ def draw: () { (Window) -> (Element | Scene | nil) } -> void
55
+ def request_frame: () -> bool
56
+ def dirty?: () -> bool
57
+ def closed?: () -> bool
58
+ def displays: () -> Array[Display]
59
+ def resize: (Numeric width, Numeric height) -> void
60
+ def input: (Input::event event) -> void
61
+ def offer_tooltip: (String text, position: Point, ?delay: Numeric) -> void
62
+ def context_menu: (menu items, ?position: Point) -> void
63
+ def close: () -> bool?
64
+ def tick: () -> void
65
+ def render: (Element element, ?clear: color, ?present: bool) -> void
66
+ def element_state: [T] (Object key) { () -> T } -> T
67
+ def write_png: (String path) -> Integer
68
+ end
69
+ end
70
+ module TUI
71
+ class InputDecoder
72
+ attr_reader buffer: String
73
+ def initialize: () { (Input::event) -> untyped } -> void
74
+ def feed: (String bytes) -> self
75
+ def flush_escape: () -> bool
76
+ end
77
+ class Window < Headless::Window
78
+ def initialize: (?input: IO, ?output: IO, ?width: Numeric, ?height: Numeric, ?title: String, ?scale_factor: Numeric) -> void
79
+ def run: () -> void
80
+ def feed_input: (String bytes) -> void
81
+ end
82
+ class TextRenderer
83
+ attr_reader runs: Array[[Numeric, Numeric, String?, color, Bounds?]]
84
+ attr_accessor scale_factor: Numeric?
85
+ def initialize: () -> void
86
+ def start_frame: () -> void
87
+ def end_frame: () -> void
88
+ def close: () -> void
89
+ def layout_line: (String text, ?font: TextSystem::_Font?, ?size: Numeric) -> TextSystem::LineLayout
90
+ def paint_line: (Scene scene, TextSystem::LineLayout line, x: Numeric, y: Numeric, ?color: color, ?spans: TextSystem::spans?) -> void
91
+ end
92
+ end
93
+ end
94
+ end
data/sig/scene.rbs ADDED
@@ -0,0 +1,52 @@
1
+ module Zaniah
2
+ interface _Rectangle
3
+ def x: () -> Numeric
4
+ def y: () -> Numeric
5
+ def width: () -> Numeric
6
+ def height: () -> Numeric
7
+ end
8
+
9
+ class Scene
10
+ QUAD_STRIDE: Integer
11
+ SPRITE_INSTANCE_BYTES: Integer
12
+ type primitive = :quad | :sprite | :sprite_batch | :triangle
13
+ class SpriteBatch < Data
14
+ attr_reader bytes: String
15
+ attr_reader texture: GPU::Texture
16
+ def self.new: (String bytes, GPU::Texture texture) -> SpriteBatch
17
+ | (bytes: String, texture: GPU::Texture) -> SpriteBatch
18
+ end
19
+ attr_reader quads: Array[Numeric]
20
+ attr_reader sprites: Array[Numeric]
21
+ attr_reader sprite_batches: Array[SpriteBatch]
22
+ attr_reader paths: Array[Numeric]
23
+ attr_reader textures: Array[GPU::Texture]
24
+ attr_reader commands: Array[primitive | Numeric | Bounds | nil]
25
+ def initialize: () -> void
26
+ def clear: () -> self
27
+ def quad: (Numeric x, Numeric y, Numeric width, Numeric height, color: color, ?radius: radius, ?border_width: Numeric, ?border_color: color) -> self
28
+ def push_quad: (Numeric x, Numeric y, Numeric width, Numeric height, color bg, radius radius, Numeric border_width, color border_color, ?Numeric order) -> self
29
+ def sprite: (Numeric x, Numeric y, Numeric width, Numeric height, texture: GPU::Texture, ?color: color, ?source: _Rectangle?) -> self
30
+ def sprite_batch: (String bytes, texture: GPU::Texture) -> self
31
+ | (SpriteBatch batch) -> self
32
+ def sprite_data: () -> Array[Numeric]
33
+ def expand_sprite_batch: (Integer index) -> [Integer, Integer]
34
+ def triangle: ([Numeric, Numeric, Numeric, Numeric, Numeric, Numeric] points, color: color) -> self
35
+ def shadow: (Numeric x, Numeric y, Numeric width, Numeric height, ?color: color, ?blur: Numeric, ?radius: Numeric) -> self
36
+ def underline: (Numeric x, Numeric y, Numeric width, color: color, ?thickness: Numeric, ?wave: bool) -> self
37
+ def clip: [T] (Bounds bounds) { () -> T } -> T
38
+ def current_clip: () -> Bounds?
39
+ def layer: [T] (Numeric order) { () -> T } -> T
40
+ def each_command: () { (primitive, Integer, Bounds?) -> void } -> void
41
+ | () -> Enumerator[[primitive, Integer, Bounds?], void]
42
+ end
43
+ class QuadPacker
44
+ attr_reader bytes: String
45
+ def initialize: () -> void
46
+ def pack: (Scene scene) -> String
47
+ end
48
+ class SceneRenderer
49
+ def initialize: (GPU::_Device device) -> void
50
+ def render: (Scene scene, ?clear: color) -> void
51
+ end
52
+ end
data/sig/shaper.rbs ADDED
@@ -0,0 +1,8 @@
1
+ module Zaniah
2
+ module TextSystem
3
+ class Shaper
4
+ def initialize: () -> void
5
+ def shape: (Array[Glyph] glyphs, size: Numeric, ?text: String?, ?script: String?, ?language: String?) -> Array[Glyph]
6
+ end
7
+ end
8
+ end
data/sig/text.rbs ADDED
@@ -0,0 +1,137 @@
1
+ module Zaniah
2
+ module TextSystem
3
+ type spans = Array[[Integer, Integer, color]]
4
+ # Structural font contracts keep signatures independent of a separately
5
+ # installed Alhena gem.
6
+ interface _Font
7
+ def units_per_em: () -> Integer
8
+ def ascent: () -> Integer
9
+ def descent: () -> Integer
10
+ def family: () -> String?
11
+ def glyph_id: (String | Integer character, ?variation_selector: String | Integer | nil) -> Integer
12
+ def advance: (Integer glyph, ?size: Numeric, ?vertical: bool) -> Float
13
+ def tables: () -> Hash[String, [Integer, Integer]]
14
+ end
15
+ interface _Bitmap
16
+ def width: () -> Integer
17
+ def height: () -> Integer
18
+ def left: () -> Integer
19
+ def top: () -> Integer
20
+ end
21
+ interface _Rasterizer
22
+ def rasterize: (_Font font, Integer glyph, size: Numeric, ?subpixel_x: Numeric) -> _Bitmap
23
+ end
24
+ interface _FontDB
25
+ def find: (?family: String?, ?weight: Integer, ?width: Integer, ?style: :normal | :italic | :oblique) -> _Font
26
+ def fallback: (Integer codepoint, _Font primary) -> _Font
27
+ end
28
+ interface _Shaper
29
+ def shape: (Array[Glyph] glyphs, size: Numeric, text: String) -> Array[Glyph]
30
+ end
31
+ interface _Segmenter
32
+ def grapheme_clusters: (String text) -> Array[String]
33
+ end
34
+ interface _System
35
+ def scale_factor=: (Numeric scale) -> Numeric
36
+ def layout_line: (String text, ?font: _Font?, ?size: Numeric) -> LineLayout
37
+ def paint_line: (Scene scene, LineLayout line, x: Numeric, y: Numeric, ?color: color, ?spans: spans?) -> void
38
+ def end_frame: () -> void
39
+ def close: () -> void
40
+ end
41
+ class FontDB
42
+ class Face < Data
43
+ attr_reader path: String
44
+ attr_reader index: Integer
45
+ attr_reader family: String
46
+ attr_reader families: Array[String]
47
+ attr_reader weight: Integer
48
+ attr_reader width: Integer
49
+ attr_reader style: :normal | :italic | :oblique
50
+ attr_reader fixed_pitch: bool
51
+ attr_reader tables: Hash[String, [Integer, Integer]]
52
+ def self.new: (String path, Integer index, String family, Array[String] families, Integer weight, Integer width, :normal | :italic | :oblique style, bool fixed_pitch, Hash[String, [Integer, Integer]] tables) -> Face
53
+ | (path: String, index: Integer, family: String, families: Array[String], weight: Integer, width: Integer, style: :normal | :italic | :oblique, fixed_pitch: bool, tables: Hash[String, [Integer, Integer]]) -> Face
54
+ end
55
+ attr_reader paths: Array[String]
56
+ def initialize: (?paths: Array[String]?) -> void
57
+ def open: (String path, ?index: Integer) -> _Font
58
+ def find: (?family: String?, ?weight: Integer, ?width: Integer, ?style: :normal | :italic | :oblique) -> _Font
59
+ def faces: () -> Array[Face]
60
+ def refresh: () -> self
61
+ def fallback: (Integer codepoint, _Font primary) -> _Font
62
+ end
63
+ class Atlas
64
+ class Entry < Data
65
+ attr_reader texture: GPU::Texture
66
+ attr_reader x: Integer
67
+ attr_reader y: Integer
68
+ attr_reader width: Integer
69
+ attr_reader height: Integer
70
+ attr_reader left: Integer
71
+ attr_reader top: Integer
72
+ def self.new: (GPU::Texture texture, Integer x, Integer y, Integer width, Integer height, Integer left, Integer top) -> Entry
73
+ | (texture: GPU::Texture, x: Integer, y: Integer, width: Integer, height: Integer, left: Integer, top: Integer) -> Entry
74
+ end
75
+ attr_reader generation: Integer
76
+ attr_reader texture: GPU::Texture
77
+ def initialize: (?width: Integer, ?height: Integer, ?format: GPU::format) -> void
78
+ def fetch: (Object key) { () -> _Bitmap } -> Entry
79
+ def lookup: (Object key) -> Entry?
80
+ def load_cache: (String path, key: String, ?preserve: bool) -> bool
81
+ def save_cache: (String path, key: String) -> bool
82
+ def end_frame: () -> void
83
+ end
84
+ class Glyph < Data
85
+ attr_reader font: _Font
86
+ attr_reader id: Integer
87
+ attr_reader start: Integer
88
+ attr_reader finish: Integer
89
+ attr_reader x: Numeric
90
+ attr_reader advance: Numeric
91
+ def self.new: (_Font font, Integer id, Integer start, Integer finish, Numeric x, Numeric advance) -> Glyph
92
+ | (font: _Font, id: Integer, start: Integer, finish: Integer, x: Numeric, advance: Numeric) -> Glyph
93
+ end
94
+ class LineLayout < Data
95
+ attr_reader text: String
96
+ attr_reader glyphs: Array[Glyph]
97
+ attr_reader width: Numeric
98
+ attr_reader ascent: Numeric
99
+ attr_reader descent: Numeric
100
+ attr_reader size: Numeric
101
+ attr_reader carets: Array[[Integer, Numeric]]
102
+ def self.new: (String text, Array[Glyph] glyphs, Numeric width, Numeric ascent, Numeric descent, Numeric size, Array[[Integer, Numeric]] carets) -> LineLayout
103
+ | (text: String, glyphs: Array[Glyph], width: Numeric, ascent: Numeric, descent: Numeric, size: Numeric, carets: Array[[Integer, Numeric]]) -> LineLayout
104
+ def index_for_x: (Numeric x) -> Integer
105
+ def x_for_index: (Integer index) -> Numeric
106
+ end
107
+ class Typesetter
108
+ class CopyError < Error
109
+ end
110
+ attr_reader font_db: _FontDB
111
+ attr_reader font: _Font
112
+ attr_reader shaper: _Shaper
113
+ attr_reader segmenter: _Segmenter
114
+ def initialize: (?font: _Font?, ?font_db: :native | _FontDB, ?capacity: Integer, ?shaper: :native | _Shaper, ?segmenter: :native | _Segmenter) -> void
115
+ def layout_line: (String text, ?font: _Font?, ?size: Numeric) -> LineLayout
116
+ def fork: (?capacity: Integer) -> Typesetter
117
+ def close: () -> void
118
+ end
119
+ class Renderer < Typesetter
120
+ MAX_PAINT_BYTES: Integer
121
+ attr_reader font_db: _FontDB
122
+ attr_reader shaper: _Shaper
123
+ attr_reader segmenter: _Segmenter
124
+ attr_reader atlas: Atlas
125
+ attr_reader color_atlas: Atlas
126
+ attr_reader font: _Font
127
+ attr_reader cache_dir: String?
128
+ attr_accessor scale_factor: Numeric
129
+ def initialize: (?font: _Font?, ?font_db: :native | _FontDB, ?capacity: Integer, ?font_raster: :native | :alhena | :core_text | :coretext | :freetype | _Rasterizer, ?shaper: :native | _Shaper, ?segmenter: :native | _Segmenter, ?cache_dir: String?) -> void
130
+ def layout_line: (String text, ?font: _Font?, ?size: Numeric) -> LineLayout
131
+ def paint_line: (Scene scene, LineLayout line, x: Numeric, y: Numeric, ?color: color, ?spans: spans?) -> void
132
+ def end_frame: () -> void
133
+ def prewarm: (?String text, ?size: Numeric) -> self
134
+ def close: () -> void
135
+ end
136
+ end
137
+ end
data/sig/zaniah.rbs ADDED
@@ -0,0 +1,120 @@
1
+ module Zaniah
2
+ VERSION: String
3
+ type color = Color | String | [Numeric, Numeric, Numeric] | [Numeric, Numeric, Numeric, Numeric]
4
+ type dimension = Numeric | Length | :auto
5
+ type radius = Numeric | [Numeric, Numeric, Numeric, Numeric]
6
+ type menu = Array[[String, (^( ) -> void)?]]
7
+
8
+ class Error < StandardError
9
+ end
10
+
11
+ class Configuration < Struct[Symbol | TextSystem::_Rasterizer | TextSystem::_FontDB | TextSystem::_Shaper | TextSystem::_Segmenter]
12
+ attr_accessor font_raster: Symbol | TextSystem::_Rasterizer
13
+ attr_accessor shaper: Symbol | TextSystem::_Shaper
14
+ attr_accessor font_db: Symbol | TextSystem::_FontDB
15
+ attr_accessor segmenter: Symbol | TextSystem::_Segmenter
16
+ def self.new: (?font_raster: Symbol | TextSystem::_Rasterizer, ?shaper: Symbol | TextSystem::_Shaper, ?font_db: Symbol | TextSystem::_FontDB, ?segmenter: Symbol | TextSystem::_Segmenter) -> Configuration
17
+ end
18
+ def self.configuration: () -> Configuration
19
+ def self.configure: [T] () { (Configuration) -> T } -> T
20
+
21
+ class Point < Data
22
+ attr_reader x: Numeric
23
+ attr_reader y: Numeric
24
+ def self.new: (Numeric x, Numeric y) -> Point
25
+ | (x: Numeric, y: Numeric) -> Point
26
+ def +: (Point other) -> Point
27
+ def -: (Point other) -> Point
28
+ end
29
+ class Size < Data
30
+ attr_reader width: Numeric
31
+ attr_reader height: Numeric
32
+ def self.new: (Numeric width, Numeric height) -> Size
33
+ | (width: Numeric, height: Numeric) -> Size
34
+ end
35
+ class Edges < Data
36
+ attr_reader top: Numeric
37
+ attr_reader right: Numeric
38
+ attr_reader bottom: Numeric
39
+ attr_reader left: Numeric
40
+ def self.new: (Numeric top, Numeric right, Numeric bottom, Numeric left) -> Edges
41
+ | (top: Numeric, right: Numeric, bottom: Numeric, left: Numeric) -> Edges
42
+ def self.all: (Numeric value) -> Edges
43
+ end
44
+ class Corners < Data
45
+ attr_reader top_left: Numeric
46
+ attr_reader top_right: Numeric
47
+ attr_reader bottom_right: Numeric
48
+ attr_reader bottom_left: Numeric
49
+ def self.new: (Numeric top_left, Numeric top_right, Numeric bottom_right, Numeric bottom_left) -> Corners
50
+ | (top_left: Numeric, top_right: Numeric, bottom_right: Numeric, bottom_left: Numeric) -> Corners
51
+ def self.all: (Numeric value) -> Corners
52
+ end
53
+ class Bounds < Data
54
+ attr_reader x: Numeric
55
+ attr_reader y: Numeric
56
+ attr_reader width: Numeric
57
+ attr_reader height: Numeric
58
+ def self.new: (Numeric x, Numeric y, Numeric width, Numeric height) -> Bounds
59
+ | (x: Numeric, y: Numeric, width: Numeric, height: Numeric) -> Bounds
60
+ def right: () -> Numeric
61
+ def bottom: () -> Numeric
62
+ def contains?: (Point point) -> bool
63
+ def intersect: (Bounds other) -> Bounds
64
+ def inset: (Numeric | Edges edges) -> Bounds
65
+ end
66
+ class Length < Data
67
+ attr_reader value: Numeric
68
+ attr_reader unit: :px | :rem | :percent
69
+ def self.new: (Numeric value, :px | :rem | :percent unit) -> Length
70
+ | (value: Numeric, unit: :px | :rem | :percent) -> Length
71
+ def resolve: (Numeric available, ?rem: Numeric) -> Numeric
72
+ end
73
+ class DevicePixels < Data
74
+ attr_reader value: Numeric
75
+ def self.new: (Numeric value) -> DevicePixels
76
+ | (value: Numeric) -> DevicePixels
77
+ def logical: (Numeric scale) -> Numeric
78
+ end
79
+ module LengthUnits
80
+ def px: (Numeric value) -> Length
81
+ def rems: (Numeric value) -> Length
82
+ def percent: (Numeric value) -> Length
83
+ end
84
+ extend LengthUnits
85
+
86
+ class Color < Data
87
+ attr_reader r: Numeric
88
+ attr_reader g: Numeric
89
+ attr_reader b: Numeric
90
+ attr_reader a: Numeric
91
+ def self.new: (Numeric r, Numeric g, Numeric b, Numeric a) -> Color
92
+ | (r: Numeric, g: Numeric, b: Numeric, a: Numeric) -> Color
93
+ def self.parse: (color value) -> Color
94
+ def opacity: (Numeric value) -> Color
95
+ def premultiplied: () -> [Numeric, Numeric, Numeric, Numeric]
96
+ def to_a: () -> [Numeric, Numeric, Numeric, Numeric]
97
+ def mix: (color other, Numeric amount) -> Color
98
+ def to_hsla: () -> HSLA
99
+ end
100
+ class HSLA < Data
101
+ attr_reader h: Numeric
102
+ attr_reader s: Numeric
103
+ attr_reader l: Numeric
104
+ attr_reader a: Numeric
105
+ def self.new: (Numeric h, Numeric s, Numeric l, Numeric a) -> HSLA
106
+ | (h: Numeric, s: Numeric, l: Numeric, a: Numeric) -> HSLA
107
+ def to_rgba: () -> Color
108
+ end
109
+
110
+ module Unicode
111
+ def self.grapheme_clusters: (String text) -> Array[String]
112
+ def self.width: (String text, ?ambiguous: 1 | 2) -> Integer
113
+ end
114
+ module PNG
115
+ SIGNATURE: String
116
+ def self.encode: (Integer width, Integer height, String rgba) -> String
117
+ def self.decode: (String bytes, ?max_pixels: Integer) -> [Integer, Integer, String]
118
+ def self.write: (String path, Integer width, Integer height, String rgba) -> Integer
119
+ end
120
+ end