ratatui_ruby 1.4.0-x86_64-linux

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 (292) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +15 -0
  3. data/LICENSES/AGPL-3.0-or-later.txt +661 -0
  4. data/LICENSES/CC-BY-SA-4.0.txt +427 -0
  5. data/LICENSES/CC0-1.0.txt +121 -0
  6. data/LICENSES/LGPL-3.0-or-later.txt +304 -0
  7. data/LICENSES/MIT-0.txt +16 -0
  8. data/LICENSES/MIT.txt +21 -0
  9. data/REUSE.toml +42 -0
  10. data/exe/.gitkeep +0 -0
  11. data/ext/ratatui_ruby/.cargo/config.toml +13 -0
  12. data/ext/ratatui_ruby/.gitignore +4 -0
  13. data/ext/ratatui_ruby/Cargo.lock +1737 -0
  14. data/ext/ratatui_ruby/Cargo.toml +24 -0
  15. data/ext/ratatui_ruby/clippy.toml +7 -0
  16. data/ext/ratatui_ruby/extconf.rb +21 -0
  17. data/ext/ratatui_ruby/src/color.rs +82 -0
  18. data/ext/ratatui_ruby/src/errors.rs +28 -0
  19. data/ext/ratatui_ruby/src/events.rs +700 -0
  20. data/ext/ratatui_ruby/src/frame.rs +241 -0
  21. data/ext/ratatui_ruby/src/lib.rs +343 -0
  22. data/ext/ratatui_ruby/src/lib_header.rs +11 -0
  23. data/ext/ratatui_ruby/src/rendering.rs +158 -0
  24. data/ext/ratatui_ruby/src/string_width.rs +101 -0
  25. data/ext/ratatui_ruby/src/style.rs +469 -0
  26. data/ext/ratatui_ruby/src/terminal/capabilities.rs +46 -0
  27. data/ext/ratatui_ruby/src/terminal/init.rs +233 -0
  28. data/ext/ratatui_ruby/src/terminal/mod.rs +42 -0
  29. data/ext/ratatui_ruby/src/terminal/mutations.rs +158 -0
  30. data/ext/ratatui_ruby/src/terminal/queries.rs +231 -0
  31. data/ext/ratatui_ruby/src/terminal/query.rs +400 -0
  32. data/ext/ratatui_ruby/src/terminal/storage.rs +109 -0
  33. data/ext/ratatui_ruby/src/terminal/wrapper.rs +16 -0
  34. data/ext/ratatui_ruby/src/text.rs +225 -0
  35. data/ext/ratatui_ruby/src/widgets/barchart.rs +169 -0
  36. data/ext/ratatui_ruby/src/widgets/block.rs +41 -0
  37. data/ext/ratatui_ruby/src/widgets/calendar.rs +84 -0
  38. data/ext/ratatui_ruby/src/widgets/canvas.rs +183 -0
  39. data/ext/ratatui_ruby/src/widgets/center.rs +79 -0
  40. data/ext/ratatui_ruby/src/widgets/chart.rs +222 -0
  41. data/ext/ratatui_ruby/src/widgets/clear.rs +39 -0
  42. data/ext/ratatui_ruby/src/widgets/cursor.rs +32 -0
  43. data/ext/ratatui_ruby/src/widgets/gauge.rs +65 -0
  44. data/ext/ratatui_ruby/src/widgets/layout.rs +379 -0
  45. data/ext/ratatui_ruby/src/widgets/line_gauge.rs +100 -0
  46. data/ext/ratatui_ruby/src/widgets/list.rs +378 -0
  47. data/ext/ratatui_ruby/src/widgets/list_state.rs +173 -0
  48. data/ext/ratatui_ruby/src/widgets/mod.rs +26 -0
  49. data/ext/ratatui_ruby/src/widgets/overlay.rs +24 -0
  50. data/ext/ratatui_ruby/src/widgets/paragraph.rs +87 -0
  51. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +40 -0
  52. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +55 -0
  53. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +214 -0
  54. data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
  55. data/ext/ratatui_ruby/src/widgets/sparkline.rs +127 -0
  56. data/ext/ratatui_ruby/src/widgets/table.rs +415 -0
  57. data/ext/ratatui_ruby/src/widgets/table_state.rs +203 -0
  58. data/ext/ratatui_ruby/src/widgets/tabs.rs +194 -0
  59. data/lib/ratatui_ruby/backend/window_size.rb +50 -0
  60. data/lib/ratatui_ruby/backend.rb +59 -0
  61. data/lib/ratatui_ruby/buffer/cell.rb +212 -0
  62. data/lib/ratatui_ruby/buffer.rb +149 -0
  63. data/lib/ratatui_ruby/cell.rb +208 -0
  64. data/lib/ratatui_ruby/debug.rb +215 -0
  65. data/lib/ratatui_ruby/draw.rb +63 -0
  66. data/lib/ratatui_ruby/event/focus_gained.rb +125 -0
  67. data/lib/ratatui_ruby/event/focus_lost.rb +127 -0
  68. data/lib/ratatui_ruby/event/key/character.rb +53 -0
  69. data/lib/ratatui_ruby/event/key/dwim.rb +301 -0
  70. data/lib/ratatui_ruby/event/key/media.rb +46 -0
  71. data/lib/ratatui_ruby/event/key/modifier.rb +107 -0
  72. data/lib/ratatui_ruby/event/key/navigation.rb +72 -0
  73. data/lib/ratatui_ruby/event/key/system.rb +47 -0
  74. data/lib/ratatui_ruby/event/key.rb +479 -0
  75. data/lib/ratatui_ruby/event/mouse.rb +291 -0
  76. data/lib/ratatui_ruby/event/none.rb +53 -0
  77. data/lib/ratatui_ruby/event/paste.rb +130 -0
  78. data/lib/ratatui_ruby/event/resize.rb +221 -0
  79. data/lib/ratatui_ruby/event/sync.rb +52 -0
  80. data/lib/ratatui_ruby/event.rb +163 -0
  81. data/lib/ratatui_ruby/frame.rb +257 -0
  82. data/lib/ratatui_ruby/labs/a11y.rb +182 -0
  83. data/lib/ratatui_ruby/labs/frame_a11y_capture.rb +50 -0
  84. data/lib/ratatui_ruby/labs.rb +47 -0
  85. data/lib/ratatui_ruby/layout/alignment.rb +91 -0
  86. data/lib/ratatui_ruby/layout/constraint.rb +337 -0
  87. data/lib/ratatui_ruby/layout/layout.rb +258 -0
  88. data/lib/ratatui_ruby/layout/position.rb +81 -0
  89. data/lib/ratatui_ruby/layout/rect.rb +733 -0
  90. data/lib/ratatui_ruby/layout/size.rb +62 -0
  91. data/lib/ratatui_ruby/layout.rb +29 -0
  92. data/lib/ratatui_ruby/list_state.rb +201 -0
  93. data/lib/ratatui_ruby/output_guard.rb +171 -0
  94. data/lib/ratatui_ruby/ratatui_ruby.so +0 -0
  95. data/lib/ratatui_ruby/scrollbar_state.rb +122 -0
  96. data/lib/ratatui_ruby/style/color.rb +149 -0
  97. data/lib/ratatui_ruby/style/style.rb +147 -0
  98. data/lib/ratatui_ruby/style.rb +19 -0
  99. data/lib/ratatui_ruby/symbols.rb +435 -0
  100. data/lib/ratatui_ruby/synthetic_events.rb +106 -0
  101. data/lib/ratatui_ruby/table_state.rb +251 -0
  102. data/lib/ratatui_ruby/terminal/capabilities.rb +316 -0
  103. data/lib/ratatui_ruby/terminal/viewport.rb +80 -0
  104. data/lib/ratatui_ruby/terminal.rb +66 -0
  105. data/lib/ratatui_ruby/terminal_lifecycle.rb +303 -0
  106. data/lib/ratatui_ruby/terminal_lifecycle.rb.bak +197 -0
  107. data/lib/ratatui_ruby/test_helper/event_injection.rb +241 -0
  108. data/lib/ratatui_ruby/test_helper/global_state.rb +111 -0
  109. data/lib/ratatui_ruby/test_helper/snapshot.rb +568 -0
  110. data/lib/ratatui_ruby/test_helper/snapshots/axis_labels_alignment.ansi +24 -0
  111. data/lib/ratatui_ruby/test_helper/snapshots/axis_labels_alignment.txt +24 -0
  112. data/lib/ratatui_ruby/test_helper/snapshots/barchart_styled_label.ansi +5 -0
  113. data/lib/ratatui_ruby/test_helper/snapshots/barchart_styled_label.txt +5 -0
  114. data/lib/ratatui_ruby/test_helper/snapshots/chart_rendering.ansi +24 -0
  115. data/lib/ratatui_ruby/test_helper/snapshots/chart_rendering.txt +24 -0
  116. data/lib/ratatui_ruby/test_helper/snapshots/half_block_marker.ansi +12 -0
  117. data/lib/ratatui_ruby/test_helper/snapshots/half_block_marker.txt +12 -0
  118. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_bottom.ansi +12 -0
  119. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_bottom.txt +12 -0
  120. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_left.ansi +12 -0
  121. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_left.txt +12 -0
  122. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_right.ansi +12 -0
  123. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_right.txt +12 -0
  124. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_top.ansi +12 -0
  125. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_top.txt +12 -0
  126. data/lib/ratatui_ruby/test_helper/snapshots/my_snapshot.txt +1 -0
  127. data/lib/ratatui_ruby/test_helper/snapshots/styled_axis_title.ansi +10 -0
  128. data/lib/ratatui_ruby/test_helper/snapshots/styled_axis_title.txt +10 -0
  129. data/lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.ansi +10 -0
  130. data/lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.txt +10 -0
  131. data/lib/ratatui_ruby/test_helper/style_assertions.rb +449 -0
  132. data/lib/ratatui_ruby/test_helper/subprocess_timeout.rb +35 -0
  133. data/lib/ratatui_ruby/test_helper/terminal.rb +187 -0
  134. data/lib/ratatui_ruby/test_helper/test_doubles.rb +86 -0
  135. data/lib/ratatui_ruby/test_helper.rb +115 -0
  136. data/lib/ratatui_ruby/text/line.rb +245 -0
  137. data/lib/ratatui_ruby/text/span.rb +158 -0
  138. data/lib/ratatui_ruby/text.rb +99 -0
  139. data/lib/ratatui_ruby/tui/buffer_factories.rb +22 -0
  140. data/lib/ratatui_ruby/tui/canvas_factories.rb +149 -0
  141. data/lib/ratatui_ruby/tui/core.rb +67 -0
  142. data/lib/ratatui_ruby/tui/layout_factories.rb +153 -0
  143. data/lib/ratatui_ruby/tui/state_factories.rb +77 -0
  144. data/lib/ratatui_ruby/tui/style_factories.rb +22 -0
  145. data/lib/ratatui_ruby/tui/text_factories.rb +86 -0
  146. data/lib/ratatui_ruby/tui/widget_factories.rb +272 -0
  147. data/lib/ratatui_ruby/tui.rb +106 -0
  148. data/lib/ratatui_ruby/version.rb +12 -0
  149. data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +51 -0
  150. data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +29 -0
  151. data/lib/ratatui_ruby/widgets/bar_chart.rb +308 -0
  152. data/lib/ratatui_ruby/widgets/block.rb +266 -0
  153. data/lib/ratatui_ruby/widgets/calendar.rb +88 -0
  154. data/lib/ratatui_ruby/widgets/canvas.rb +297 -0
  155. data/lib/ratatui_ruby/widgets/cell.rb +59 -0
  156. data/lib/ratatui_ruby/widgets/center.rb +71 -0
  157. data/lib/ratatui_ruby/widgets/chart.rb +172 -0
  158. data/lib/ratatui_ruby/widgets/clear.rb +66 -0
  159. data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
  160. data/lib/ratatui_ruby/widgets/cursor.rb +54 -0
  161. data/lib/ratatui_ruby/widgets/gauge.rb +146 -0
  162. data/lib/ratatui_ruby/widgets/line_gauge.rb +158 -0
  163. data/lib/ratatui_ruby/widgets/list.rb +252 -0
  164. data/lib/ratatui_ruby/widgets/list_item.rb +55 -0
  165. data/lib/ratatui_ruby/widgets/overlay.rb +55 -0
  166. data/lib/ratatui_ruby/widgets/paragraph.rb +113 -0
  167. data/lib/ratatui_ruby/widgets/ratatui_logo.rb +35 -0
  168. data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +40 -0
  169. data/lib/ratatui_ruby/widgets/row.rb +123 -0
  170. data/lib/ratatui_ruby/widgets/scrollbar.rb +147 -0
  171. data/lib/ratatui_ruby/widgets/shape/label.rb +80 -0
  172. data/lib/ratatui_ruby/widgets/sparkline.rb +153 -0
  173. data/lib/ratatui_ruby/widgets/table.rb +213 -0
  174. data/lib/ratatui_ruby/widgets/tabs.rb +91 -0
  175. data/lib/ratatui_ruby/widgets.rb +43 -0
  176. data/lib/ratatui_ruby.rb +555 -0
  177. data/sig/examples/app_all_events/app.rbs +11 -0
  178. data/sig/examples/app_all_events/model/app_model.rbs +23 -0
  179. data/sig/examples/app_all_events/model/event_entry.rbs +23 -0
  180. data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
  181. data/sig/examples/app_all_events/view/app_view.rbs +8 -0
  182. data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
  183. data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
  184. data/sig/examples/app_all_events/view/live_view.rbs +6 -0
  185. data/sig/examples/app_all_events/view/log_view.rbs +6 -0
  186. data/sig/examples/app_all_events/view.rbs +14 -0
  187. data/sig/examples/app_cli_rich_moments/app.rbs +12 -0
  188. data/sig/examples/app_color_picker/app.rbs +17 -0
  189. data/sig/examples/app_external_editor/app.rbs +12 -0
  190. data/sig/examples/app_login_form/app.rbs +11 -0
  191. data/sig/examples/app_stateful_interaction/app.rbs +39 -0
  192. data/sig/examples/verify_quickstart_dsl/app.rbs +17 -0
  193. data/sig/examples/verify_quickstart_lifecycle/app.rbs +17 -0
  194. data/sig/examples/verify_readme_usage/app.rbs +17 -0
  195. data/sig/examples/widget_block_demo/app.rbs +38 -0
  196. data/sig/examples/widget_box_demo/app.rbs +17 -0
  197. data/sig/examples/widget_calendar_demo/app.rbs +17 -0
  198. data/sig/examples/widget_cell_demo/app.rbs +17 -0
  199. data/sig/examples/widget_chart_demo/app.rbs +17 -0
  200. data/sig/examples/widget_gauge_demo/app.rbs +17 -0
  201. data/sig/examples/widget_layout_split/app.rbs +16 -0
  202. data/sig/examples/widget_line_gauge_demo/app.rbs +17 -0
  203. data/sig/examples/widget_list_demo/app.rbs +17 -0
  204. data/sig/examples/widget_map_demo/app.rbs +17 -0
  205. data/sig/examples/widget_popup_demo/app.rbs +17 -0
  206. data/sig/examples/widget_ratatui_logo_demo/app.rbs +17 -0
  207. data/sig/examples/widget_ratatui_mascot_demo/app.rbs +17 -0
  208. data/sig/examples/widget_rect/app.rbs +18 -0
  209. data/sig/examples/widget_render/app.rbs +16 -0
  210. data/sig/examples/widget_rich_text/app.rbs +17 -0
  211. data/sig/examples/widget_scroll_text/app.rbs +17 -0
  212. data/sig/examples/widget_scrollbar_demo/app.rbs +17 -0
  213. data/sig/examples/widget_sparkline_demo/app.rbs +16 -0
  214. data/sig/examples/widget_style_colors/app.rbs +20 -0
  215. data/sig/examples/widget_table_demo/app.rbs +17 -0
  216. data/sig/examples/widget_text_width/app.rbs +16 -0
  217. data/sig/generated/event_key_predicates.rbs +1348 -0
  218. data/sig/manifest.yaml +5 -0
  219. data/sig/patches/data.rbs +26 -0
  220. data/sig/patches/debugger__.rbs +8 -0
  221. data/sig/ratatui_ruby/backend/window_size.rbs +17 -0
  222. data/sig/ratatui_ruby/backend.rbs +12 -0
  223. data/sig/ratatui_ruby/buffer/cell.rbs +46 -0
  224. data/sig/ratatui_ruby/buffer.rbs +18 -0
  225. data/sig/ratatui_ruby/cell.rbs +44 -0
  226. data/sig/ratatui_ruby/clear.rbs +18 -0
  227. data/sig/ratatui_ruby/constraint.rbs +26 -0
  228. data/sig/ratatui_ruby/debug.rbs +45 -0
  229. data/sig/ratatui_ruby/draw.rbs +30 -0
  230. data/sig/ratatui_ruby/event.rbs +249 -0
  231. data/sig/ratatui_ruby/frame.rbs +23 -0
  232. data/sig/ratatui_ruby/interfaces.rbs +25 -0
  233. data/sig/ratatui_ruby/labs.rbs +90 -0
  234. data/sig/ratatui_ruby/layout/alignment.rbs +26 -0
  235. data/sig/ratatui_ruby/layout/constraint.rbs +39 -0
  236. data/sig/ratatui_ruby/layout/layout.rbs +45 -0
  237. data/sig/ratatui_ruby/layout/position.rbs +18 -0
  238. data/sig/ratatui_ruby/layout/rect.rbs +64 -0
  239. data/sig/ratatui_ruby/layout/size.rbs +18 -0
  240. data/sig/ratatui_ruby/list_state.rbs +23 -0
  241. data/sig/ratatui_ruby/output_guard.rbs +23 -0
  242. data/sig/ratatui_ruby/ratatui_ruby.rbs +113 -0
  243. data/sig/ratatui_ruby/rect.rbs +17 -0
  244. data/sig/ratatui_ruby/scrollbar_state.rbs +24 -0
  245. data/sig/ratatui_ruby/session.rbs +93 -0
  246. data/sig/ratatui_ruby/style/color.rbs +22 -0
  247. data/sig/ratatui_ruby/style/style.rbs +29 -0
  248. data/sig/ratatui_ruby/symbols.rbs +141 -0
  249. data/sig/ratatui_ruby/synthetic_events.rbs +24 -0
  250. data/sig/ratatui_ruby/table_state.rbs +27 -0
  251. data/sig/ratatui_ruby/terminal/capabilities.rbs +38 -0
  252. data/sig/ratatui_ruby/terminal/viewport.rbs +33 -0
  253. data/sig/ratatui_ruby/terminal_lifecycle.rbs +39 -0
  254. data/sig/ratatui_ruby/test_helper/event_injection.rbs +22 -0
  255. data/sig/ratatui_ruby/test_helper/snapshot.rbs +37 -0
  256. data/sig/ratatui_ruby/test_helper/style_assertions.rbs +77 -0
  257. data/sig/ratatui_ruby/test_helper/terminal.rbs +20 -0
  258. data/sig/ratatui_ruby/test_helper/test_doubles.rbs +32 -0
  259. data/sig/ratatui_ruby/test_helper.rbs +18 -0
  260. data/sig/ratatui_ruby/text/line.rbs +27 -0
  261. data/sig/ratatui_ruby/text/span.rbs +23 -0
  262. data/sig/ratatui_ruby/text.rbs +12 -0
  263. data/sig/ratatui_ruby/tui/buffer_factories.rbs +16 -0
  264. data/sig/ratatui_ruby/tui/canvas_factories.rbs +38 -0
  265. data/sig/ratatui_ruby/tui/core.rbs +23 -0
  266. data/sig/ratatui_ruby/tui/layout_factories.rbs +39 -0
  267. data/sig/ratatui_ruby/tui/state_factories.rbs +23 -0
  268. data/sig/ratatui_ruby/tui/style_factories.rbs +18 -0
  269. data/sig/ratatui_ruby/tui/text_factories.rbs +23 -0
  270. data/sig/ratatui_ruby/tui/widget_factories.rbs +138 -0
  271. data/sig/ratatui_ruby/tui.rbs +25 -0
  272. data/sig/ratatui_ruby/version.rbs +12 -0
  273. data/sig/ratatui_ruby/widgets/bar_chart.rbs +95 -0
  274. data/sig/ratatui_ruby/widgets/block.rbs +51 -0
  275. data/sig/ratatui_ruby/widgets/calendar.rbs +45 -0
  276. data/sig/ratatui_ruby/widgets/canvas.rbs +95 -0
  277. data/sig/ratatui_ruby/widgets/chart.rbs +91 -0
  278. data/sig/ratatui_ruby/widgets/coerceable_widget.rbs +26 -0
  279. data/sig/ratatui_ruby/widgets/gauge.rbs +44 -0
  280. data/sig/ratatui_ruby/widgets/line_gauge.rbs +48 -0
  281. data/sig/ratatui_ruby/widgets/list.rbs +63 -0
  282. data/sig/ratatui_ruby/widgets/misc.rbs +158 -0
  283. data/sig/ratatui_ruby/widgets/paragraph.rbs +45 -0
  284. data/sig/ratatui_ruby/widgets/row.rbs +43 -0
  285. data/sig/ratatui_ruby/widgets/scrollbar.rbs +53 -0
  286. data/sig/ratatui_ruby/widgets/shape/label.rbs +37 -0
  287. data/sig/ratatui_ruby/widgets/sparkline.rbs +45 -0
  288. data/sig/ratatui_ruby/widgets/table.rbs +78 -0
  289. data/sig/ratatui_ruby/widgets/tabs.rbs +44 -0
  290. data/sig/ratatui_ruby/widgets.rbs +16 -0
  291. data/vendor/goodcop/base.yml +1047 -0
  292. metadata +729 -0
@@ -0,0 +1,297 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ module RatatuiRuby
9
+ module Widgets
10
+ # Namespace for canvas shape primitives (Point, Line, Rectangle, Circle, Map, Label).
11
+ # Distinct from text components and other Line usages.
12
+ module Shape
13
+ # A point in the canvas coordinate system.
14
+ #
15
+ # [x] The x-coordinate.
16
+ # [y] The y-coordinate.
17
+ class Point < Data.define(:x, :y)
18
+ ##
19
+ # :attr_reader: x
20
+ # X coordinate (Float, duck-typed via +to_f+).
21
+
22
+ ##
23
+ # :attr_reader: y
24
+ # Y coordinate (Float, duck-typed via +to_f+).
25
+
26
+ # Creates a new Point.
27
+ #
28
+ # [x] X coordinate (Numeric).
29
+ # [y] Y coordinate (Numeric).
30
+ def initialize(x:, y:)
31
+ super(x: Float(x), y: Float(y))
32
+ end
33
+ end
34
+
35
+ # A line shape on a canvas.
36
+ #
37
+ # [x1] The starting x-coordinate.
38
+ # [y1] The starting y-coordinate.
39
+ # [x2] The ending x-coordinate.
40
+ # [y2] The ending y-coordinate.
41
+ # [color] The color of the line.
42
+ class Line < Data.define(:x1, :y1, :x2, :y2, :color)
43
+ ##
44
+ # :attr_reader: x1
45
+ # Start X (Float, duck-typed via +to_f+).
46
+
47
+ ##
48
+ # :attr_reader: y1
49
+ # Start Y (Float, duck-typed via +to_f+).
50
+
51
+ ##
52
+ # :attr_reader: x2
53
+ # End X (Float, duck-typed via +to_f+).
54
+
55
+ ##
56
+ # :attr_reader: y2
57
+ # End Y (Float, duck-typed via +to_f+).
58
+
59
+ ##
60
+ # :attr_reader: color
61
+ # Line color.
62
+
63
+ # Creates a new Line.
64
+ #
65
+ # [x1] Start X (Numeric).
66
+ # [y1] Start Y (Numeric).
67
+ # [x2] End X (Numeric).
68
+ # [y2] End Y (Numeric).
69
+ # [color] Line color (Symbol).
70
+ def initialize(x1:, y1:, x2:, y2:, color:)
71
+ super(x1: Float(x1), y1: Float(y1), x2: Float(x2), y2: Float(y2), color:)
72
+ end
73
+ end
74
+
75
+ # A rectangle shape on a canvas.
76
+ #
77
+ # [x] The x-coordinate of the bottom-left corner.
78
+ # [y] The y-coordinate of the bottom-left corner.
79
+ # [width] The width of the rectangle.
80
+ # [height] The height of the rectangle.
81
+ # [color] The color of the rectangle.
82
+ class Rectangle < Data.define(:x, :y, :width, :height, :color)
83
+ ##
84
+ # :attr_reader: x
85
+ # Bottom-left X (Float, duck-typed via +to_f+).
86
+
87
+ ##
88
+ # :attr_reader: y
89
+ # Bottom-left Y (Float, duck-typed via +to_f+).
90
+
91
+ ##
92
+ # :attr_reader: width
93
+ # Width (Float, duck-typed via +to_f+).
94
+
95
+ ##
96
+ # :attr_reader: height
97
+ # Height (Float, duck-typed via +to_f+).
98
+
99
+ ##
100
+ # :attr_reader: color
101
+ # Color.
102
+
103
+ # Creates a new Rectangle.
104
+ #
105
+ # [x] Bottom-left X (Numeric).
106
+ # [y] Bottom-left Y (Numeric).
107
+ # [width] Width (Numeric).
108
+ # [height] Height (Numeric).
109
+ # [color] Color (Symbol).
110
+ def initialize(x:, y:, width:, height:, color:)
111
+ super(x: Float(x), y: Float(y), width: Float(width), height: Float(height), color:)
112
+ end
113
+ end
114
+
115
+ # A circle shape on a canvas.
116
+ #
117
+ # [x] The x-coordinate of the center.
118
+ # [y] The y-coordinate of the center.
119
+ # [radius] The radius of the circle.
120
+ # [color] The color of the circle.
121
+ class Circle < Data.define(:x, :y, :radius, :color)
122
+ ##
123
+ # :attr_reader: x
124
+ # Center X (Float, duck-typed via +to_f+).
125
+
126
+ ##
127
+ # :attr_reader: y
128
+ # Center Y (Float, duck-typed via +to_f+).
129
+
130
+ ##
131
+ # :attr_reader: radius
132
+ # Radius (Float, duck-typed via +to_f+).
133
+
134
+ ##
135
+ # :attr_reader: color
136
+ # Color.
137
+
138
+ # Creates a new Circle.
139
+ #
140
+ # [x] Center X (Numeric).
141
+ # [y] Center Y (Numeric).
142
+ # [radius] Radius (Numeric).
143
+ # [color] Color (Symbol).
144
+ def initialize(x:, y:, radius:, color:)
145
+ super(x: Float(x), y: Float(y), radius: Float(radius), color:)
146
+ end
147
+ end
148
+
149
+ # A world map shape on a canvas.
150
+ #
151
+ # [color] The color of the map.
152
+ # [resolution] The resolution of the map (<tt>:low</tt>, <tt>:high</tt>).
153
+ class Map < Data.define(:color, :resolution)
154
+ ##
155
+ # :attr_reader: color
156
+ # Map color.
157
+
158
+ ##
159
+ # :attr_reader: resolution
160
+ # Resolution (<tt>:low</tt> or <tt>:high</tt>).
161
+ end
162
+ end
163
+
164
+ # Provides a drawing surface for custom shapes.
165
+ #
166
+ # Standard widgets cover standard cases. Sometimes you need to draw a map, a custom diagram, or a game.
167
+ # Character grids are too coarse for fine detail.
168
+ #
169
+ # This widget increases the resolution. It uses Braille patterns or block characters to create a "sub-pixel" drawing surface.
170
+ #
171
+ # Use it to implement free-form graphics, high-resolution plots, or geographic maps.
172
+ #
173
+ # === Examples
174
+ #
175
+ #--
176
+ # SPDX-SnippetBegin
177
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
178
+ # SPDX-License-Identifier: MIT-0
179
+ #++
180
+ # Canvas.new(
181
+ # x_bounds: [-180, 180],
182
+ # y_bounds: [-90, 90],
183
+ # shapes: [
184
+ # Shape::Map.new(color: :green, resolution: :high),
185
+ # Shape::Circle.new(x: 0, y: 0, radius: 10, color: :red),
186
+ # Shape::Label.new(x: -122.4, y: 37.8, text: "San Francisco")
187
+ # ]
188
+ # )
189
+ #--
190
+ # SPDX-SnippetEnd
191
+ #++
192
+ class Canvas < Data.define(:shapes, :x_bounds, :y_bounds, :marker, :block, :background_color)
193
+ include CoerceableWidget
194
+
195
+ ##
196
+ # :attr_reader: shapes
197
+ # Array of shapes to render.
198
+ #
199
+ # Includes {Shape::Line}, {Shape::Circle}, {Shape::Map}, etc.
200
+
201
+ ##
202
+ # :attr_reader: x_bounds
203
+ # [min, max] range for the x-axis.
204
+
205
+ ##
206
+ # :attr_reader: y_bounds
207
+ # [min, max] range for the y-axis.
208
+
209
+ ##
210
+ # :attr_reader: marker
211
+ # The marker type used for drawing.
212
+ #
213
+ # <tt>:braille</tt> (high res), <tt>:half_block</tt>, <tt>:dot</tt>, <tt>:block</tt>, <tt>:bar</tt>.
214
+
215
+ ##
216
+ # :attr_reader: block
217
+ # Optional wrapping block.
218
+
219
+ ##
220
+ # :attr_reader: background_color
221
+ # The background color of the canvas.
222
+
223
+ # Creates a new Canvas.
224
+ #
225
+ # [shapes] Array of Shapes.
226
+ # [x_bounds] Array of [min, max] (Numeric, duck-typed via +to_f+).
227
+ # [y_bounds] Array of [min, max] (Numeric, duck-typed via +to_f+).
228
+ # [marker] Symbol (default: <tt>:braille</tt>).
229
+ # [block] Block (optional).
230
+ # [background_color] Color (optional).
231
+ def initialize(shapes: [], x_bounds: [0.0, 100.0], y_bounds: [0.0, 100.0], marker: :braille, block: nil, background_color: nil)
232
+ super(
233
+ shapes:,
234
+ x_bounds: [Float(x_bounds[0]), Float(x_bounds[1])],
235
+ y_bounds: [Float(y_bounds[0]), Float(y_bounds[1])],
236
+ marker:,
237
+ block:,
238
+ background_color:
239
+ )
240
+ end
241
+
242
+ # Converts canvas coordinates to normalized grid coordinates.
243
+ #
244
+ # Hit testing and layout decisions need to know where a canvas point
245
+ # falls within the drawing surface. This method maps from the canvas
246
+ # coordinate system to normalized [0.0, 1.0] coordinates.
247
+ #
248
+ # Use it to determine if a click or touch event lands within the
249
+ # canvas bounds, and where proportionally.
250
+ #
251
+ # [x] X coordinate in canvas coordinate system.
252
+ # [y] Y coordinate in canvas coordinate system.
253
+ #
254
+ # Returns an Array <tt>[normalized_x, normalized_y]</tt> where each
255
+ # value is between 0.0 and 1.0, or <tt>nil</tt> if the point is
256
+ # outside the canvas bounds.
257
+ #
258
+ # === Example
259
+ #
260
+ #--
261
+ # SPDX-SnippetBegin
262
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
263
+ # SPDX-License-Identifier: MIT-0
264
+ #++
265
+ # canvas = Canvas.new(x_bounds: [0.0, 100.0], y_bounds: [0.0, 50.0])
266
+ # canvas.get_point(50.0, 25.0) # => [0.5, 0.5] (center)
267
+ # canvas.get_point(0.0, 0.0) # => [0.0, 1.0] (bottom-left)
268
+ # canvas.get_point(101.0, 0.0) # => nil (out of bounds)
269
+ #--
270
+ # SPDX-SnippetEnd
271
+ #++
272
+ def get_point(x, y)
273
+ left, right = x_bounds
274
+ bottom, top = y_bounds
275
+
276
+ # Check bounds
277
+ return nil if x < left || x > right || y < bottom || y > top
278
+
279
+ width = right - left
280
+ height = top - bottom
281
+
282
+ # Avoid division by zero
283
+ return nil if width <= 0.0 || height <= 0.0
284
+
285
+ # Normalize to [0.0, 1.0] range
286
+ normalized_x = (x - left) / width
287
+ normalized_y = (top - y) / height # Y inverted: top is 0, bottom is 1
288
+
289
+ [normalized_x, normalized_y]
290
+ end
291
+
292
+ # Ruby-idiomatic aliases (TIMTOWTDI)
293
+ alias point get_point
294
+ alias [] get_point
295
+ end
296
+ end
297
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ module RatatuiRuby
9
+ module Widgets
10
+ # A styled table cell combining content with optional styling.
11
+ #
12
+ # By default, Table cells are plain strings. For more control over cell styling,
13
+ # wrap the content in a Cell object to apply cell-level background style.
14
+ #
15
+ # The content can be a String, Text::Span, or Text::Line.
16
+ # The style applies to the entire cell area (background).
17
+ #
18
+ # === Examples
19
+ #
20
+ #--
21
+ # SPDX-SnippetBegin
22
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
23
+ # SPDX-License-Identifier: MIT-0
24
+ #++
25
+ # # Cell with yellow background
26
+ # Widgets::Cell.new(content: "Warning", style: Style::Style.new(bg: :yellow))
27
+ #
28
+ # # Cell with rich text content
29
+ # Widgets::Cell.new(
30
+ # content: Text::Line.new(spans: [
31
+ # Text::Span.new(content: "Error: ", style: Style::Style.new(fg: :red)),
32
+ # Text::Span.new(content: "Details here")
33
+ # ]),
34
+ # style: Style::Style.new(bg: :dark_gray)
35
+ # )
36
+ #--
37
+ # SPDX-SnippetEnd
38
+ #++
39
+ class Cell < Data.define(:content, :style)
40
+ include CoerceableWidget
41
+
42
+ ##
43
+ # :attr_reader: content
44
+ # The content to display (String, Text::Span, or Text::Line).
45
+
46
+ ##
47
+ # :attr_reader: style
48
+ # The style to apply to the cell area (optional Style::Style).
49
+
50
+ # Creates a new Cell.
51
+ #
52
+ # [content] String, Text::Span, or Text::Line.
53
+ # [style] Style::Style object (optional).
54
+ def initialize(content:, style: nil)
55
+ super
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ module RatatuiRuby
9
+ module Widgets
10
+ # Centers content within available space.
11
+ #
12
+ # Layouts often require alignment. Manually calculating offsets for centering is error-prone and brittle.
13
+ #
14
+ # This widget handles the math. It centers a child widget within the current area, resizing the child
15
+ # according to optional percentage modifiers.
16
+ #
17
+ # Use it to position modals, splash screens, or floating dialogue boxes.
18
+ #
19
+ # === Examples
20
+ #
21
+ #--
22
+ # SPDX-SnippetBegin
23
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
24
+ # SPDX-License-Identifier: MIT-0
25
+ #++
26
+ # # Center a paragraph using 50% of width and height
27
+ # Center.new(
28
+ # child: Paragraph.new(text: "Hello"),
29
+ # width_percent: 50,
30
+ # height_percent: 50
31
+ # )
32
+ #--
33
+ # SPDX-SnippetEnd
34
+ #++
35
+ class Center < Data.define(:child, :width_percent, :height_percent)
36
+ include CoerceableWidget
37
+
38
+ ##
39
+ # :attr_reader: child
40
+ # The widget to be centered.
41
+
42
+ ##
43
+ # :attr_reader: width_percent
44
+ # Width of the centered area as a percentage (0-100).
45
+ #
46
+ # If 50, the child occupies half the available width.
47
+
48
+ ##
49
+ # :attr_reader: height_percent
50
+ # Height of the centered area as a percentage (0-100).
51
+ #
52
+ # If 50, the child occupies half the available height.
53
+
54
+ # Creates a new Center widget.
55
+ #
56
+ # [child]
57
+ # Widget to render.
58
+ # [width_percent]
59
+ # Target width percentage (Integer, default: 100).
60
+ # [height_percent]
61
+ # Target height percentage (Integer, default: 100).
62
+ def initialize(child:, width_percent: 100, height_percent: 100)
63
+ super(
64
+ child:,
65
+ width_percent: Float(width_percent),
66
+ height_percent: Float(height_percent)
67
+ )
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ module RatatuiRuby
9
+ module Widgets
10
+ # Defines an Axis for a Chart
11
+ # [title] String
12
+ # [bounds] Array<Float> [min, max]
13
+ # [labels] Array<String>
14
+ # [style] Style
15
+ # [labels_alignment] Symbol (<tt>:left</tt>, <tt>:center</tt>, <tt>:right</tt>)
16
+ class Axis < Data.define(:title, :bounds, :labels, :style, :labels_alignment)
17
+ include CoerceableWidget
18
+
19
+ ##
20
+ # :attr_reader: title
21
+ # Label for the axis (String).
22
+
23
+ ##
24
+ # :attr_reader: bounds
25
+ # Range [min, max] (Array of Floats).
26
+
27
+ ##
28
+ # :attr_reader: labels
29
+ # Explicit labels for ticks (Array of Strings).
30
+
31
+ ##
32
+ # :attr_reader: style
33
+ # Style for axis lines/text.
34
+
35
+ ##
36
+ # :attr_reader: labels_alignment
37
+ # Alignment of axis labels (:left, :center, :right).
38
+
39
+ # Creates a new Axis.
40
+ #
41
+ # [title] String.
42
+ # [bounds] Array [min, max].
43
+ # [labels] Array of Strings.
44
+ # [style] Style.
45
+ # [labels_alignment] Symbol (:left, :center, :right).
46
+ def initialize(title: "", bounds: [0.0, 10.0], labels: [], style: nil, labels_alignment: nil)
47
+ super(
48
+ title:,
49
+ bounds: [Float(bounds[0]), Float(bounds[1])],
50
+ labels:,
51
+ style:,
52
+ labels_alignment:
53
+ )
54
+ end
55
+ end
56
+
57
+ # Defines a Dataset for a Chart.
58
+ # [name] The name of the dataset.
59
+ # [data] Array of arrays [[x, y], [x, y]] (Floats).
60
+ # [style] The style of the line.
61
+ # [marker] Symbol (<tt>:dot</tt>, <tt>:braille</tt>, <tt>:block</tt>, <tt>:bar</tt>, <tt>:half_block</tt>)
62
+ # [graph_type] Symbol (<tt>:line</tt>, <tt>:scatter</tt>)
63
+ class Dataset < Data.define(:name, :data, :style, :marker, :graph_type)
64
+ include CoerceableWidget
65
+
66
+ ##
67
+ # :attr_reader: name
68
+ # Name for logical identification or legend.
69
+
70
+ ##
71
+ # :attr_reader: data
72
+ # list of [x, y] coordinates.
73
+
74
+ ##
75
+ # :attr_reader: style
76
+ # Style applied to the dataset (Style).
77
+ #
78
+ # **Note**: Due to Ratatui's Chart widget design, only the foreground color (<tt>fg</tt>) is applied to markers in the chart area.
79
+ # The full style (including <tt>bg</tt> and <tt>modifiers</tt>) is displayed in the legend.
80
+ #
81
+ # Supports:
82
+ # - +fg+: Foreground color of markers (Symbol/Hex) - _applied to chart_
83
+ # - +bg+: Background color (Symbol/Hex) - _legend only_
84
+ # - +modifiers+: Array of effects (<tt>:bold</tt>, <tt>:dim</tt>, <tt>:italic</tt>, <tt>:underlined</tt>, <tt>:slow_blink</tt>, <tt>:rapid_blink</tt>, <tt>:reversed</tt>, <tt>:hidden</tt>, <tt>:crossed_out</tt>) - _legend only_
85
+
86
+ ##
87
+ # :attr_reader: marker
88
+ # Marker type (<tt>:dot</tt>, <tt>:braille</tt>, <tt>:block</tt>, <tt>:bar</tt>, <tt>:half_block</tt>).
89
+ #
90
+ # <tt>:half_block</tt> uses ▀ and ▄ characters for higher resolution than <tt>:dot</tt>.
91
+
92
+ ##
93
+ # :attr_reader: graph_type
94
+ # Type of graph (<tt>:line</tt>, <tt>:scatter</tt>).
95
+
96
+ # Creates a new Dataset.
97
+ #
98
+ # [name] String.
99
+ # [data] Array of [x, y] (Numeric, duck-typed via +to_f+).
100
+ # [style] Style.
101
+ # [marker] Symbol.
102
+ # [graph_type] Symbol.
103
+ def initialize(name:, data:, style: nil, marker: :dot, graph_type: :line)
104
+ coerced_data = data.map { |point| [Float(point[0]), Float(point[1])] }
105
+ super(name:, data: coerced_data, style:, marker:, graph_type:)
106
+ end
107
+ end
108
+
109
+ # Plots data points on a Cartesian coordinate system.
110
+ #
111
+ # Trends and patterns are invisible in raw logs. You need to see the shape of the data to understand the story it tells.
112
+ #
113
+ # This widget plots X/Y coordinates. It supports multiple datasets, custom axes, and different marker types.
114
+ #
115
+ # Use it for analytics, scientific data, or monitoring metrics over time.
116
+ #
117
+ # {rdoc-image:/doc/images/widget_chart.png}[link:/examples/widget_chart/app_rb.html]
118
+ #
119
+ # === Example
120
+ #
121
+ # Run the interactive demo from the terminal:
122
+ #
123
+ # ruby examples/widget_chart/app.rb
124
+ class Chart < Data.define(:datasets, :x_axis, :y_axis, :block, :style, :legend_position, :hidden_legend_constraints)
125
+ include CoerceableWidget
126
+
127
+ ##
128
+ # :attr_reader: datasets
129
+ # Array of Dataset objects to plot.
130
+
131
+ ##
132
+ # :attr_reader: x_axis
133
+ # Configuration for the X Axis.
134
+
135
+ ##
136
+ # :attr_reader: y_axis
137
+ # Configuration for the Y Axis.
138
+
139
+ ##
140
+ # :attr_reader: block
141
+ # Optional wrapping block.
142
+
143
+ ##
144
+ # :attr_reader: style
145
+ # Base style for the chart area.
146
+
147
+ ##
148
+ # :attr_reader: legend_position
149
+ # Position of the legend.
150
+ #
151
+ # Corners: <tt>:top_left</tt>, <tt>:top_right</tt>, <tt>:bottom_left</tt>, <tt>:bottom_right</tt>.
152
+ # Edges: <tt>:top</tt>, <tt>:bottom</tt>, <tt>:left</tt>, <tt>:right</tt>.
153
+
154
+ ##
155
+ # :attr_reader: hidden_legend_constraints
156
+ # Constraints for hiding the legend when the chart is too small (Array of [width, height]).
157
+
158
+ # Creates a new Chart widget.
159
+ #
160
+ # [datasets] Array of Datasets.
161
+ # [x_axis] X Axis config.
162
+ # [y_axis] Y Axis config.
163
+ # [block] Wrapper (optional).
164
+ # [style] Base style (optional).
165
+ # [legend_position] Symbol — corners: <tt>:top_left</tt>, <tt>:top_right</tt>, <tt>:bottom_left</tt>, <tt>:bottom_right</tt>; edges: <tt>:top</tt>, <tt>:bottom</tt>, <tt>:left</tt>, <tt>:right</tt>.
166
+ # [hidden_legend_constraints] Array of two Constraints [width, height] (optional).
167
+ def initialize(datasets:, x_axis:, y_axis:, block: nil, style: nil, legend_position: nil, hidden_legend_constraints: [])
168
+ super
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ module RatatuiRuby
9
+ module Widgets
10
+ # Resets the terminal buffer for a specific area.
11
+ #
12
+ # Painting in a terminal is additive. New content draws over old content. If the new content has transparency
13
+ # or empty spaces, the old content "bleeds" through. This ruins popups and modals.
14
+ #
15
+ # This widget wipes the slate clean. It resets all cells in its area to their default state (spaces with default background).
16
+ #
17
+ # Use it as the first layer in an Overlay stack when building popups. Ensure your floating windows are truly opaque.
18
+ #
19
+ # === Examples
20
+ #
21
+ #--
22
+ # SPDX-SnippetBegin
23
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
24
+ # SPDX-License-Identifier: MIT-0
25
+ #++
26
+ # # Opaque Popup Construction
27
+ # Overlay.new(
28
+ # layers: [
29
+ # MainUI.new,
30
+ # Center.new(
31
+ # child: Overlay.new(
32
+ # layers: [
33
+ # Clear.new, # Wipe the area first
34
+ # Block.new(title: "Modal", borders: [:all])
35
+ # ]
36
+ # ),
37
+ # width_percent: 50,
38
+ # height_percent: 50
39
+ # )
40
+ # ]
41
+ # )
42
+ #
43
+ # # Shortcut: rendering a block directly
44
+ # Clear.new(block: Block.new(title: "Cleared area", borders: [:all]))
45
+ #--
46
+ # SPDX-SnippetEnd
47
+ #++
48
+ class Clear < Data.define(:block)
49
+ include CoerceableWidget
50
+
51
+ ##
52
+ # :attr_reader: block
53
+ # Optional Block to render after clearing.
54
+ #
55
+ # If provided, the borders/title of this block are drawn on top of the cleared area.
56
+
57
+ # Creates a new Clear widget.
58
+ #
59
+ # [block]
60
+ # Block widget to render (optional).
61
+ def initialize(block: nil)
62
+ super
63
+ end
64
+ end
65
+ end
66
+ end