ratatui_ruby 0.3.1 → 0.4.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 (300) hide show
  1. checksums.yaml +4 -4
  2. data/.builds/ruby-3.2.yml +14 -12
  3. data/.builds/ruby-3.3.yml +14 -12
  4. data/.builds/ruby-3.4.yml +14 -12
  5. data/.builds/ruby-4.0.0.yml +14 -12
  6. data/AGENTS.md +54 -13
  7. data/CHANGELOG.md +186 -1
  8. data/README.md +17 -15
  9. data/doc/application_architecture.md +116 -0
  10. data/doc/application_testing.md +12 -7
  11. data/doc/contributors/better_dx.md +543 -0
  12. data/doc/contributors/design/ruby_frontend.md +1 -1
  13. data/doc/contributors/developing_examples.md +203 -0
  14. data/doc/contributors/documentation_style.md +97 -0
  15. data/doc/contributors/dwim_dx.md +366 -0
  16. data/doc/contributors/example_analysis.md +82 -0
  17. data/doc/custom.css +14 -0
  18. data/doc/event_handling.md +119 -0
  19. data/doc/images/all_events.png +0 -0
  20. data/doc/images/analytics.png +0 -0
  21. data/doc/images/block_padding.png +0 -0
  22. data/doc/images/block_titles.png +0 -0
  23. data/doc/images/box_demo.png +0 -0
  24. data/doc/images/calendar_demo.png +0 -0
  25. data/doc/images/cell_demo.png +0 -0
  26. data/doc/images/chart_demo.png +0 -0
  27. data/doc/images/custom_widget.png +0 -0
  28. data/doc/images/flex_layout.png +0 -0
  29. data/doc/images/gauge_demo.png +0 -0
  30. data/doc/images/hit_test.png +0 -0
  31. data/doc/images/line_gauge_demo.png +0 -0
  32. data/doc/images/list_demo.png +0 -0
  33. data/doc/images/list_styles.png +0 -0
  34. data/doc/images/login_form.png +0 -0
  35. data/doc/images/map_demo.png +0 -0
  36. data/doc/images/mouse_events.png +0 -0
  37. data/doc/images/popup_demo.png +0 -0
  38. data/doc/images/quickstart_dsl.png +0 -0
  39. data/doc/images/quickstart_lifecycle.png +0 -0
  40. data/doc/images/ratatui_logo_demo.png +0 -0
  41. data/doc/images/readme_usage.png +0 -0
  42. data/doc/images/rich_text.png +0 -0
  43. data/doc/images/scroll_text.png +0 -0
  44. data/doc/images/scrollbar_demo.png +0 -0
  45. data/doc/images/sparkline_demo.png +0 -0
  46. data/doc/images/table_flex.png +0 -0
  47. data/doc/images/table_select.png +0 -0
  48. data/doc/images/widget_style_colors.png +0 -0
  49. data/doc/index.md +1 -0
  50. data/doc/interactive_design.md +121 -0
  51. data/doc/quickstart.md +147 -72
  52. data/examples/all_events/app.rb +169 -0
  53. data/examples/all_events/app.rbs +7 -0
  54. data/examples/all_events/test_app.rb +139 -0
  55. data/examples/analytics/app.rb +258 -0
  56. data/examples/analytics/app.rbs +7 -0
  57. data/examples/analytics/test_app.rb +132 -0
  58. data/examples/block_padding/app.rb +63 -0
  59. data/examples/block_padding/app.rbs +7 -0
  60. data/examples/block_padding/test_app.rb +31 -0
  61. data/examples/block_titles/app.rb +61 -0
  62. data/examples/block_titles/app.rbs +7 -0
  63. data/examples/block_titles/test_app.rb +34 -0
  64. data/examples/box_demo/app.rb +216 -0
  65. data/examples/box_demo/app.rbs +7 -0
  66. data/examples/box_demo/test_app.rb +88 -0
  67. data/examples/calendar_demo/app.rb +101 -0
  68. data/examples/calendar_demo/app.rbs +7 -0
  69. data/examples/calendar_demo/test_app.rb +108 -0
  70. data/examples/cell_demo/app.rb +108 -0
  71. data/examples/cell_demo/app.rbs +7 -0
  72. data/examples/cell_demo/test_app.rb +36 -0
  73. data/examples/chart_demo/app.rb +203 -0
  74. data/examples/chart_demo/app.rbs +7 -0
  75. data/examples/chart_demo/test_app.rb +102 -0
  76. data/examples/custom_widget/app.rb +51 -0
  77. data/examples/custom_widget/app.rbs +7 -0
  78. data/examples/custom_widget/test_app.rb +30 -0
  79. data/examples/flex_layout/app.rb +156 -0
  80. data/examples/flex_layout/app.rbs +7 -0
  81. data/examples/flex_layout/test_app.rb +65 -0
  82. data/examples/gauge_demo/app.rb +182 -0
  83. data/examples/gauge_demo/app.rbs +7 -0
  84. data/examples/gauge_demo/test_app.rb +120 -0
  85. data/examples/hit_test/app.rb +175 -0
  86. data/examples/hit_test/app.rbs +7 -0
  87. data/examples/hit_test/test_app.rb +102 -0
  88. data/examples/line_gauge_demo/app.rb +190 -0
  89. data/examples/line_gauge_demo/app.rbs +7 -0
  90. data/examples/line_gauge_demo/test_app.rb +129 -0
  91. data/examples/list_demo/app.rb +253 -0
  92. data/examples/list_demo/app.rbs +12 -0
  93. data/examples/list_demo/test_app.rb +237 -0
  94. data/examples/list_styles/app.rb +140 -0
  95. data/examples/list_styles/app.rbs +7 -0
  96. data/examples/list_styles/test_app.rb +157 -0
  97. data/examples/{login_form.rb → login_form/app.rb} +12 -16
  98. data/examples/login_form/app.rbs +7 -0
  99. data/examples/login_form/test_app.rb +51 -0
  100. data/examples/map_demo/app.rb +90 -0
  101. data/examples/map_demo/app.rbs +7 -0
  102. data/examples/map_demo/test_app.rb +149 -0
  103. data/examples/{mouse_events.rb → mouse_events/app.rb} +29 -27
  104. data/examples/mouse_events/app.rbs +7 -0
  105. data/examples/mouse_events/test_app.rb +53 -0
  106. data/examples/{popup_demo.rb → popup_demo/app.rb} +15 -17
  107. data/examples/popup_demo/app.rbs +7 -0
  108. data/examples/{test_popup_demo.rb → popup_demo/test_app.rb} +18 -26
  109. data/examples/quickstart_dsl/app.rb +36 -0
  110. data/examples/quickstart_dsl/app.rbs +7 -0
  111. data/examples/quickstart_dsl/test_app.rb +29 -0
  112. data/examples/quickstart_lifecycle/app.rb +39 -0
  113. data/examples/quickstart_lifecycle/app.rbs +7 -0
  114. data/examples/quickstart_lifecycle/test_app.rb +29 -0
  115. data/examples/ratatui_logo_demo/app.rb +79 -0
  116. data/examples/ratatui_logo_demo/app.rbs +7 -0
  117. data/examples/ratatui_logo_demo/test_app.rb +51 -0
  118. data/examples/ratatui_mascot_demo/app.rb +84 -0
  119. data/examples/ratatui_mascot_demo/app.rbs +7 -0
  120. data/examples/ratatui_mascot_demo/test_app.rb +47 -0
  121. data/examples/readme_usage/app.rb +29 -0
  122. data/examples/readme_usage/app.rbs +7 -0
  123. data/examples/readme_usage/test_app.rb +29 -0
  124. data/examples/rich_text/app.rb +141 -0
  125. data/examples/rich_text/app.rbs +7 -0
  126. data/examples/rich_text/test_app.rb +166 -0
  127. data/examples/scroll_text/app.rb +103 -0
  128. data/examples/scroll_text/app.rbs +7 -0
  129. data/examples/scroll_text/test_app.rb +110 -0
  130. data/examples/scrollbar_demo/app.rb +143 -0
  131. data/examples/scrollbar_demo/app.rbs +7 -0
  132. data/examples/scrollbar_demo/test_app.rb +77 -0
  133. data/examples/sparkline_demo/app.rb +240 -0
  134. data/examples/sparkline_demo/app.rbs +10 -0
  135. data/examples/sparkline_demo/test_app.rb +107 -0
  136. data/examples/table_flex/app.rb +65 -0
  137. data/examples/table_flex/app.rbs +7 -0
  138. data/examples/table_flex/test_app.rb +36 -0
  139. data/examples/table_select/app.rb +198 -0
  140. data/examples/table_select/app.rbs +7 -0
  141. data/examples/table_select/test_app.rb +180 -0
  142. data/examples/widget_style_colors/app.rb +104 -0
  143. data/examples/widget_style_colors/app.rbs +14 -0
  144. data/examples/widget_style_colors/test_app.rb +48 -0
  145. data/ext/ratatui_ruby/Cargo.lock +889 -115
  146. data/ext/ratatui_ruby/Cargo.toml +4 -3
  147. data/ext/ratatui_ruby/clippy.toml +7 -0
  148. data/ext/ratatui_ruby/extconf.rb +7 -0
  149. data/ext/ratatui_ruby/src/events.rs +218 -229
  150. data/ext/ratatui_ruby/src/lib.rs +38 -10
  151. data/ext/ratatui_ruby/src/rendering.rs +90 -10
  152. data/ext/ratatui_ruby/src/style.rs +281 -98
  153. data/ext/ratatui_ruby/src/terminal.rs +119 -25
  154. data/ext/ratatui_ruby/src/text.rs +171 -0
  155. data/ext/ratatui_ruby/src/widgets/barchart.rs +97 -24
  156. data/ext/ratatui_ruby/src/widgets/block.rs +31 -3
  157. data/ext/ratatui_ruby/src/widgets/calendar.rs +45 -44
  158. data/ext/ratatui_ruby/src/widgets/canvas.rs +46 -29
  159. data/ext/ratatui_ruby/src/widgets/chart.rs +69 -27
  160. data/ext/ratatui_ruby/src/widgets/clear.rs +3 -1
  161. data/ext/ratatui_ruby/src/widgets/gauge.rs +11 -4
  162. data/ext/ratatui_ruby/src/widgets/layout.rs +218 -15
  163. data/ext/ratatui_ruby/src/widgets/line_gauge.rs +92 -0
  164. data/ext/ratatui_ruby/src/widgets/list.rs +91 -11
  165. data/ext/ratatui_ruby/src/widgets/mod.rs +3 -0
  166. data/ext/ratatui_ruby/src/widgets/overlay.rs +3 -2
  167. data/ext/ratatui_ruby/src/widgets/paragraph.rs +35 -13
  168. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +29 -0
  169. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +44 -0
  170. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +59 -7
  171. data/ext/ratatui_ruby/src/widgets/sparkline.rs +70 -6
  172. data/ext/ratatui_ruby/src/widgets/table.rs +173 -64
  173. data/ext/ratatui_ruby/src/widgets/tabs.rs +105 -5
  174. data/lib/ratatui_ruby/cell.rb +166 -0
  175. data/lib/ratatui_ruby/event/focus_gained.rb +49 -0
  176. data/lib/ratatui_ruby/event/focus_lost.rb +50 -0
  177. data/lib/ratatui_ruby/event/key.rb +211 -0
  178. data/lib/ratatui_ruby/event/mouse.rb +124 -0
  179. data/lib/ratatui_ruby/event/paste.rb +71 -0
  180. data/lib/ratatui_ruby/event/resize.rb +80 -0
  181. data/lib/ratatui_ruby/event.rb +79 -0
  182. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +45 -0
  183. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +27 -0
  184. data/lib/ratatui_ruby/schema/bar_chart.rb +228 -19
  185. data/lib/ratatui_ruby/schema/block.rb +186 -14
  186. data/lib/ratatui_ruby/schema/calendar.rb +74 -17
  187. data/lib/ratatui_ruby/schema/canvas.rb +215 -48
  188. data/lib/ratatui_ruby/schema/center.rb +49 -11
  189. data/lib/ratatui_ruby/schema/chart.rb +151 -41
  190. data/lib/ratatui_ruby/schema/clear.rb +41 -72
  191. data/lib/ratatui_ruby/schema/constraint.rb +82 -22
  192. data/lib/ratatui_ruby/schema/cursor.rb +27 -9
  193. data/lib/ratatui_ruby/schema/draw.rb +53 -0
  194. data/lib/ratatui_ruby/schema/gauge.rb +59 -15
  195. data/lib/ratatui_ruby/schema/layout.rb +95 -13
  196. data/lib/ratatui_ruby/schema/line_gauge.rb +78 -0
  197. data/lib/ratatui_ruby/schema/list.rb +93 -19
  198. data/lib/ratatui_ruby/schema/overlay.rb +34 -8
  199. data/lib/ratatui_ruby/schema/paragraph.rb +87 -30
  200. data/lib/ratatui_ruby/schema/ratatui_logo.rb +25 -0
  201. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +29 -0
  202. data/lib/ratatui_ruby/schema/rect.rb +64 -15
  203. data/lib/ratatui_ruby/schema/scrollbar.rb +132 -24
  204. data/lib/ratatui_ruby/schema/shape/label.rb +66 -0
  205. data/lib/ratatui_ruby/schema/sparkline.rb +122 -15
  206. data/lib/ratatui_ruby/schema/style.rb +49 -21
  207. data/lib/ratatui_ruby/schema/table.rb +119 -21
  208. data/lib/ratatui_ruby/schema/tabs.rb +75 -13
  209. data/lib/ratatui_ruby/schema/text.rb +90 -0
  210. data/lib/ratatui_ruby/session.rb +146 -0
  211. data/lib/ratatui_ruby/test_helper.rb +156 -13
  212. data/lib/ratatui_ruby/version.rb +1 -1
  213. data/lib/ratatui_ruby.rb +143 -23
  214. data/sig/ratatui_ruby/event.rbs +69 -0
  215. data/sig/ratatui_ruby/ratatui_ruby.rbs +2 -1
  216. data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +16 -0
  217. data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +13 -0
  218. data/sig/ratatui_ruby/schema/bar_chart.rbs +20 -2
  219. data/sig/ratatui_ruby/schema/block.rbs +5 -4
  220. data/sig/ratatui_ruby/schema/calendar.rbs +6 -2
  221. data/sig/ratatui_ruby/schema/canvas.rbs +52 -39
  222. data/sig/ratatui_ruby/schema/center.rbs +3 -3
  223. data/sig/ratatui_ruby/schema/chart.rbs +8 -5
  224. data/sig/ratatui_ruby/schema/constraint.rbs +8 -5
  225. data/sig/ratatui_ruby/schema/cursor.rbs +1 -1
  226. data/sig/ratatui_ruby/schema/draw.rbs +23 -0
  227. data/sig/ratatui_ruby/schema/gauge.rbs +4 -2
  228. data/sig/ratatui_ruby/schema/layout.rbs +11 -1
  229. data/sig/ratatui_ruby/schema/line_gauge.rbs +16 -0
  230. data/sig/ratatui_ruby/schema/list.rbs +5 -1
  231. data/sig/ratatui_ruby/schema/paragraph.rbs +4 -1
  232. data/{lib/ratatui_ruby/output.rb → sig/ratatui_ruby/schema/ratatui_logo.rbs} +3 -2
  233. data/sig/ratatui_ruby/{buffer.rbs → schema/ratatui_mascot.rbs} +4 -3
  234. data/sig/ratatui_ruby/schema/rect.rbs +2 -1
  235. data/sig/ratatui_ruby/schema/scrollbar.rbs +18 -2
  236. data/sig/ratatui_ruby/schema/sparkline.rbs +6 -2
  237. data/sig/ratatui_ruby/schema/table.rbs +8 -1
  238. data/sig/ratatui_ruby/schema/tabs.rbs +5 -1
  239. data/sig/ratatui_ruby/schema/text.rbs +22 -0
  240. data/tasks/resources/build.yml.erb +13 -11
  241. data/tasks/terminal_preview/app_screenshot.rb +35 -0
  242. data/tasks/terminal_preview/crash_report.rb +54 -0
  243. data/tasks/terminal_preview/example_app.rb +25 -0
  244. data/tasks/terminal_preview/launcher_script.rb +48 -0
  245. data/tasks/terminal_preview/preview_collection.rb +60 -0
  246. data/tasks/terminal_preview/preview_timing.rb +22 -0
  247. data/tasks/terminal_preview/safety_confirmation.rb +58 -0
  248. data/tasks/terminal_preview/saved_screenshot.rb +55 -0
  249. data/tasks/terminal_preview/system_appearance.rb +11 -0
  250. data/tasks/terminal_preview/terminal_window.rb +138 -0
  251. data/tasks/terminal_preview/window_id.rb +14 -0
  252. data/tasks/terminal_preview.rake +28 -0
  253. data/tasks/test.rake +1 -1
  254. metadata +174 -53
  255. data/doc/images/examples-analytics.rb.png +0 -0
  256. data/doc/images/examples-box_demo.rb.png +0 -0
  257. data/doc/images/examples-calendar_demo.rb.png +0 -0
  258. data/doc/images/examples-chart_demo.rb.png +0 -0
  259. data/doc/images/examples-custom_widget.rb.png +0 -0
  260. data/doc/images/examples-dashboard.rb.png +0 -0
  261. data/doc/images/examples-list_styles.rb.png +0 -0
  262. data/doc/images/examples-login_form.rb.png +0 -0
  263. data/doc/images/examples-map_demo.rb.png +0 -0
  264. data/doc/images/examples-mouse_events.rb.png +0 -0
  265. data/doc/images/examples-popup_demo.rb.gif +0 -0
  266. data/doc/images/examples-quickstart_lifecycle.rb.png +0 -0
  267. data/doc/images/examples-scroll_text.rb.png +0 -0
  268. data/doc/images/examples-scrollbar_demo.rb.png +0 -0
  269. data/doc/images/examples-stock_ticker.rb.png +0 -0
  270. data/doc/images/examples-system_monitor.rb.png +0 -0
  271. data/doc/images/examples-table_select.rb.png +0 -0
  272. data/examples/analytics.rb +0 -88
  273. data/examples/box_demo.rb +0 -71
  274. data/examples/calendar_demo.rb +0 -55
  275. data/examples/chart_demo.rb +0 -84
  276. data/examples/custom_widget.rb +0 -43
  277. data/examples/dashboard.rb +0 -72
  278. data/examples/list_styles.rb +0 -66
  279. data/examples/map_demo.rb +0 -58
  280. data/examples/quickstart_dsl.rb +0 -30
  281. data/examples/quickstart_lifecycle.rb +0 -40
  282. data/examples/readme_usage.rb +0 -21
  283. data/examples/scroll_text.rb +0 -74
  284. data/examples/scrollbar_demo.rb +0 -75
  285. data/examples/stock_ticker.rb +0 -93
  286. data/examples/system_monitor.rb +0 -94
  287. data/examples/table_select.rb +0 -70
  288. data/examples/test_analytics.rb +0 -65
  289. data/examples/test_box_demo.rb +0 -38
  290. data/examples/test_calendar_demo.rb +0 -66
  291. data/examples/test_dashboard.rb +0 -38
  292. data/examples/test_list_styles.rb +0 -61
  293. data/examples/test_login_form.rb +0 -63
  294. data/examples/test_map_demo.rb +0 -100
  295. data/examples/test_scroll_text.rb +0 -130
  296. data/examples/test_stock_ticker.rb +0 -39
  297. data/examples/test_system_monitor.rb +0 -40
  298. data/examples/test_table_select.rb +0 -37
  299. data/ext/ratatui_ruby/src/buffer.rs +0 -54
  300. data/lib/ratatui_ruby/dsl.rb +0 -64
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
- # SPDX-License-Identifier: AGPL-3.0-or-later
5
-
6
- $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
- require "ratatui_ruby"
8
-
9
- # A custom widget that draws a diagonal line.
10
- class DiagonalWidget
11
- def render(area, buffer)
12
- # Draw a diagonal line within the area
13
- (0..10).each do |i|
14
- next if area.x + i >= area.x + area.width || area.y + i >= area.y + area.height
15
-
16
- buffer.set_string(
17
- area.x + i,
18
- area.y + i,
19
- "\\",
20
- RatatuiRuby::Style.new(fg: :red, modifiers: [:bold])
21
- )
22
- end
23
- end
24
- end
25
-
26
- RatatuiRuby.main_loop do |tui|
27
- tui.draw(
28
- RatatuiRuby::Layout.new(
29
- direction: :vertical,
30
- constraints: [
31
- RatatuiRuby::Constraint.percentage(50),
32
- RatatuiRuby::Constraint.percentage(50),
33
- ],
34
- children: [
35
- RatatuiRuby::Paragraph.new(text: "Above custom widget"),
36
- DiagonalWidget.new,
37
- ]
38
- )
39
- )
40
-
41
- event = RatatuiRuby.poll_event
42
- break if event && event[:type] == :key && event[:code] == "q"
43
- end
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
- # SPDX-License-Identifier: AGPL-3.0-or-later
5
-
6
- $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
- require "ratatui_ruby"
8
-
9
- include RatatuiRuby
10
-
11
- class DashboardApp
12
- include RatatuiRuby
13
-
14
- def initialize
15
- @items = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]
16
- @selected_index = 0
17
- end
18
-
19
- def run
20
- RatatuiRuby.init_terminal
21
- begin
22
- loop do
23
- render
24
- break if handle_input == :quit
25
- end
26
- ensure
27
- RatatuiRuby.restore_terminal
28
- end
29
- end
30
-
31
- def render
32
- selected_item = @items[@selected_index]
33
-
34
- sidebar = List.new(
35
- items: @items,
36
- selected_index: @selected_index,
37
- block: Block.new(title: "Files", borders: [:all])
38
- )
39
-
40
- main_content = Paragraph.new(
41
- text: "You selected: #{selected_item}",
42
- block: Block.new(title: "Content", borders: [:all])
43
- )
44
-
45
- layout = Layout.new(
46
- direction: :horizontal,
47
- constraints: [
48
- Constraint.percentage(30),
49
- Constraint.min(0),
50
- ],
51
- children: [sidebar, main_content]
52
- )
53
-
54
- RatatuiRuby.draw(layout)
55
- end
56
-
57
- def handle_input
58
- event = RatatuiRuby.poll_event
59
- if event
60
- case event[:code]
61
- when "q", "esc"
62
- :quit
63
- when "up"
64
- @selected_index = (@selected_index - 1) % @items.length
65
- when "down"
66
- @selected_index = (@selected_index + 1) % @items.length
67
- end
68
- end
69
- end
70
- end
71
-
72
- DashboardApp.new.run if __FILE__ == $0
@@ -1,66 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
- # SPDX-License-Identifier: AGPL-3.0-or-later
5
-
6
- $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
- require "ratatui_ruby"
8
-
9
- # Styled List Example
10
- # Demonstrates advanced styling options for the List widget.
11
- class ListStylesApp
12
- attr_reader :selected_index
13
-
14
- def initialize
15
- @items = ["Item 1", "Item 2", "Item 3"]
16
- @selected_index = 0
17
- end
18
-
19
- def run
20
- RatatuiRuby.init_terminal
21
- begin
22
- loop do
23
- render
24
- break if handle_input == :quit
25
- sleep 0.05
26
- end
27
- ensure
28
- RatatuiRuby.restore_terminal
29
- end
30
- end
31
-
32
- def render
33
- RatatuiRuby.draw(
34
- RatatuiRuby::List.new(
35
- items: @items,
36
- selected_index: @selected_index,
37
- style: RatatuiRuby::Style.new(fg: :white, bg: :black),
38
- highlight_style: RatatuiRuby::Style.new(fg: :blue, bg: :white, modifiers: [:bold]),
39
- highlight_symbol: ">> ",
40
- block: RatatuiRuby::Block.new(
41
- title: "Styled List (Up/Down to move, Q to quit)",
42
- borders: [:all]
43
- )
44
- )
45
- )
46
- end
47
-
48
- def handle_input
49
- event = RatatuiRuby.poll_event
50
- return nil unless event
51
-
52
- if event[:type] == :key
53
- case event[:code]
54
- when "up"
55
- @selected_index = (@selected_index - 1) % @items.size
56
- when "down"
57
- @selected_index = (@selected_index + 1) % @items.size
58
- when "q"
59
- return :quit
60
- end
61
- end
62
- nil
63
- end
64
- end
65
-
66
- ListStylesApp.new.run if __FILE__ == $PROGRAM_NAME
data/examples/map_demo.rb DELETED
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
- # SPDX-License-Identifier: AGPL-3.0-or-later
5
-
6
- $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
- require "ratatui_ruby"
8
-
9
- # An example of the Canvas widget showing a world map and animated shapes.
10
- module MapDemo
11
- include RatatuiRuby
12
-
13
- # Returns a Canvas view for the map demo with the given circle radius.
14
- #
15
- # +radius+:: The radius of the animated circle.
16
- def self.view(radius)
17
- Canvas.new(
18
- shapes: [
19
- Map.new(color: :green, resolution: :high),
20
- Circle.new(x: 0.0, y: 0.0, radius:, color: :red),
21
- Line.new(x1: 0.0, y1: 0.0, x2: 50.0, y2: 25.0, color: :yellow),
22
- ],
23
- x_bounds: [-180.0, 180.0],
24
- y_bounds: [-90.0, 90.0],
25
- marker: :braille,
26
- block: Block.new(title: "World Map Canvas", borders: :all)
27
- )
28
- end
29
-
30
- # Runs the map demo loop.
31
- def self.run
32
- RatatuiRuby.init_terminal
33
- radius = 0.0
34
- direction = 1
35
-
36
- loop do
37
- # Animate the circle radius
38
- radius += 0.5 * direction
39
- if radius > 10.0 || radius < 0.0
40
- direction *= -1
41
- end
42
-
43
- # Define the view
44
- view = view(radius)
45
-
46
- RatatuiRuby.draw(view)
47
-
48
- event = RatatuiRuby.poll_event
49
- break if event && event[:type] == :key && event[:code] == "q"
50
-
51
- sleep 0.05
52
- end
53
- ensure
54
- RatatuiRuby.restore_terminal
55
- end
56
- end
57
-
58
- MapDemo.run if __FILE__ == $PROGRAM_NAME
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
- # SPDX-License-Identifier: AGPL-3.0-or-later
5
-
6
- $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
-
8
- require "ratatui_ruby"
9
-
10
- # 1. Initialize the terminal, start the main loop, and ensure the terminal is restored.
11
- RatatuiRuby.main_loop do |tui|
12
- # 2. Create your UI with methods instead of classes.
13
- view = tui.paragraph(
14
- text: "Hello, Ratatui! Press 'q' to quit.",
15
- align: :center,
16
- block: tui.block(
17
- title: "My Ruby TUI App",
18
- borders: [:all],
19
- border_color: "cyan"
20
- )
21
- )
22
-
23
- # 3. Use RatatuiRuby methods, too.
24
- tui.draw(view)
25
- event = tui.poll_event
26
-
27
- if event && event[:type] == :key && event[:code] == "q"
28
- break
29
- end
30
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
- # SPDX-License-Identifier: AGPL-3.0-or-later
5
-
6
- $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
-
8
- require "ratatui_ruby"
9
-
10
- # 1. Initialize the terminal
11
- RatatuiRuby.init_terminal
12
-
13
- begin
14
- # The Main Loop
15
- loop do
16
- # 2. Create your UI (Immediate Mode)
17
- # We define a Paragraph widget inside a Block with a title and borders.
18
- view = RatatuiRuby::Paragraph.new(
19
- text: "Hello, Ratatui! Press 'q' to quit.",
20
- align: :center,
21
- block: RatatuiRuby::Block.new(
22
- title: "My Ruby TUI App",
23
- borders: [:all],
24
- border_color: "cyan"
25
- )
26
- )
27
-
28
- # 3. Draw the UI
29
- RatatuiRuby.draw(view)
30
-
31
- # 4. Poll for events
32
- event = RatatuiRuby.poll_event
33
- if event && event[:type] == :key && event[:code] == "q"
34
- break
35
- end
36
- end
37
- ensure
38
- # 5. Restore the terminal to its original state
39
- RatatuiRuby.restore_terminal
40
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
- # SPDX-License-Identifier: AGPL-3.0-or-later
5
-
6
- $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
-
8
- require "ratatui_ruby"
9
- RatatuiRuby.main_loop do |tui|
10
- tui.draw \
11
- tui.paragraph \
12
- text: "Hello, Ratatui! Press 'q' to quit.",
13
- align: :center,
14
- block: tui.block(
15
- title: "My Ruby TUI App",
16
- borders: [:all],
17
- border_color: "cyan"
18
- )
19
- event = tui.poll_event
20
- break if event && event[:type] == :key && event[:code] == "q"
21
- end
@@ -1,74 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
6
-
7
- $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
8
- require "ratatui_ruby"
9
-
10
- # Demo: Scrollable Paragraph
11
- # Shows how to scroll through long text content using arrow keys
12
- class ScrollTextDemo
13
- def initialize
14
- @scroll_x = 0
15
- @scroll_y = 0
16
- @lines = (1..100).map { |i| "Line #{i}: This is a long line of text that can be scrolled horizontally" }
17
- end
18
-
19
- def run
20
- RatatuiRuby.init_terminal
21
- begin
22
- loop do
23
- draw
24
- break if handle_input == :quit
25
- end
26
- ensure
27
- RatatuiRuby.restore_terminal
28
- end
29
- end
30
-
31
- def render
32
- draw
33
- end
34
-
35
- def handle_input
36
- event = RatatuiRuby.poll_event
37
- return nil unless event
38
-
39
- if event[:type] == :key
40
- case event[:code]
41
- when "up"
42
- @scroll_y = [@scroll_y - 1, 0].max
43
- when "down"
44
- @scroll_y = [@scroll_y + 1, @lines.length].min
45
- when "left"
46
- @scroll_x = [@scroll_x - 1, 0].max
47
- when "right"
48
- @scroll_x = [@scroll_x + 1, 100].min
49
- when "q"
50
- return :quit
51
- end
52
- end
53
- nil
54
- end
55
-
56
- private
57
-
58
- def draw
59
- text = @lines.join("\n")
60
-
61
- paragraph = RatatuiRuby::Paragraph.new(
62
- text: text,
63
- scroll: [@scroll_y, @scroll_x],
64
- block: RatatuiRuby::Block.new(
65
- title: "Scrollable Text (X: #{@scroll_x}, Y: #{@scroll_y}) - Arrow keys to scroll, 'q' to quit",
66
- borders: [:all]
67
- )
68
- )
69
-
70
- RatatuiRuby.draw(paragraph)
71
- end
72
- end
73
-
74
- ScrollTextDemo.new.run if __FILE__ == $PROGRAM_NAME
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
- # SPDX-License-Identifier: AGPL-3.0-or-later
5
-
6
- $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
- require "ratatui_ruby"
8
-
9
- # Simple Scrollbar Demo
10
- class ScrollbarDemo
11
- def initialize
12
- @scroll_position = 0
13
- @content_length = 50
14
- @lines = (1..@content_length).map { |i| "Line #{i}" }
15
- end
16
-
17
- def run
18
- RatatuiRuby.init_terminal
19
- begin
20
- loop do
21
- draw
22
- event = RatatuiRuby.poll_event
23
- break if event && event[:type] == :key && event[:code] == "q"
24
-
25
- handle_event(event)
26
- end
27
- ensure
28
- RatatuiRuby.restore_terminal
29
- end
30
- end
31
-
32
- private def handle_event(event)
33
- return unless event && event[:type] == :mouse
34
-
35
- case event[:kind]
36
- when :scroll_up
37
- @scroll_position = [@scroll_position - 1, 0].max
38
- when :scroll_down
39
- @scroll_position = [@scroll_position + 1, @content_length].min
40
- end
41
- end
42
-
43
- private def draw
44
- # Calculate visible lines based on scroll position
45
- # In a real app, you'd want to know the height of the available area.
46
- # For this demo, we'll just show all lines but offset the text.
47
- visible_lines = @lines[@scroll_position..-1] || []
48
-
49
- # Paragraph with content
50
- p = RatatuiRuby::Paragraph.new(
51
- text: visible_lines.join("\n"),
52
- block: RatatuiRuby::Block.new(title: "Scroll with Mouse Wheel", borders: [:all])
53
- )
54
-
55
- # Scrollbar on the right
56
- s = RatatuiRuby::Scrollbar.new(
57
- content_length: @content_length,
58
- position: @scroll_position
59
- )
60
-
61
- # Use a Layout to place scrollbar on the right
62
- layout = RatatuiRuby::Layout.new(
63
- direction: :horizontal,
64
- constraints: [
65
- RatatuiRuby::Constraint.percentage(95),
66
- RatatuiRuby::Constraint.percentage(5),
67
- ],
68
- children: [p, s]
69
- )
70
-
71
- RatatuiRuby.draw(layout)
72
- end
73
- end
74
-
75
- ScrollbarDemo.new.run if __FILE__ == $PROGRAM_NAME
@@ -1,93 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
- # SPDX-License-Identifier: AGPL-3.0-or-later
5
-
6
- $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
- require "ratatui_ruby"
8
-
9
- # Simulate a stock ticker
10
- class StockTickerApp
11
- def initialize
12
- @network_data = Array.new(50) { rand(0..10) }
13
- @ruby_stock = []
14
- @rust_stock = []
15
- @counter = 0
16
- end
17
-
18
- def run
19
- RatatuiRuby.init_terminal
20
- begin
21
- loop do
22
- render
23
- break if handle_input == :quit
24
- sleep 0.1
25
- end
26
- ensure
27
- RatatuiRuby.restore_terminal
28
- end
29
- end
30
-
31
- def render
32
- # Update data
33
- @counter += 1
34
- @network_data.shift
35
- @network_data << rand(0..10)
36
-
37
- ruby_val = 50.0 + (Math.sin(@counter * 0.1) * 20.0) + (rand * 5.0)
38
- rust_val = 40.0 + (Math.cos(@counter * 0.2) * 15.0) + (rand * 10.0)
39
-
40
- @ruby_stock << [@counter.to_f, ruby_val]
41
- @rust_stock << [@counter.to_f, rust_val]
42
-
43
- # Keep only last 100 points
44
- if @ruby_stock.length > 100
45
- @ruby_stock.shift
46
- @rust_stock.shift
47
- end
48
-
49
- # Define UI
50
- ui = RatatuiRuby::Layout.new(
51
- direction: :vertical,
52
- constraints: [
53
- RatatuiRuby::Constraint.new(type: :percentage, value: 20),
54
- RatatuiRuby::Constraint.new(type: :percentage, value: 80),
55
- ],
56
- children: [
57
- RatatuiRuby::Sparkline.new(
58
- data: @network_data,
59
- style: RatatuiRuby::Style.new(fg: :cyan),
60
- block: RatatuiRuby::Block.new(title: "Network Activity", borders: :all)
61
- ),
62
- RatatuiRuby::Chart.new(
63
- datasets: [
64
- RatatuiRuby::Dataset.new(name: "RBY", data: @ruby_stock, color: :green),
65
- RatatuiRuby::Dataset.new(name: "RST", data: @rust_stock, color: :red),
66
- ],
67
- x_axis: RatatuiRuby::Axis.new(
68
- title: "Time",
69
- bounds: [((@counter > 100) ? @counter - 100.0 : 0.0), @counter.to_f],
70
- labels: [@counter.to_s]
71
- ),
72
- y_axis: RatatuiRuby::Axis.new(
73
- title: "Price",
74
- bounds: [0.0, 100.0],
75
- labels: %w[0 50 100]
76
- ),
77
- block: RatatuiRuby::Block.new(title: "Stock Ticker", borders: :all),
78
- ),
79
- ]
80
- )
81
-
82
- RatatuiRuby.draw(ui)
83
- end
84
-
85
- def handle_input
86
- event = RatatuiRuby.poll_event
87
- if event && event[:code] == "q"
88
- :quit
89
- end
90
- end
91
- end
92
-
93
- StockTickerApp.new.run if __FILE__ == $0
@@ -1,94 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
- # SPDX-License-Identifier: AGPL-3.0-or-later
5
-
6
- $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
- require "ratatui_ruby"
8
-
9
- class SystemMonitorApp
10
- def initialize
11
- @percentage = 50
12
- end
13
-
14
- def run
15
- RatatuiRuby.init_terminal
16
- begin
17
- loop do
18
- render
19
- break if handle_input == :quit
20
- end
21
- ensure
22
- RatatuiRuby.restore_terminal
23
- end
24
- end
25
-
26
- def render
27
- # System Monitor Layout
28
- # Top: Table (50%)
29
- # Bottom: Gauge (50%)
30
-
31
- header_style = RatatuiRuby::Style.new(fg: :blue, modifiers: [:bold])
32
-
33
- header = [
34
- RatatuiRuby::Paragraph.new(text: "PID", style: header_style),
35
- RatatuiRuby::Paragraph.new(text: "Name", style: header_style),
36
- RatatuiRuby::Paragraph.new(text: "CPU%", style: header_style),
37
- RatatuiRuby::Paragraph.new(text: "Mem%", style: header_style),
38
- ]
39
-
40
- rows = [
41
- ["1234", "ruby", "0.5", "1.2"],
42
- ["5678", "rust", "10.2", "4.5"],
43
- ["9012", "system", "1.1", "0.8"],
44
- ]
45
-
46
- widths = [
47
- RatatuiRuby::Constraint.length(10),
48
- RatatuiRuby::Constraint.min(20),
49
- RatatuiRuby::Constraint.length(10),
50
- RatatuiRuby::Constraint.length(10),
51
- ]
52
-
53
- table = RatatuiRuby::Table.new(
54
- header:,
55
- rows:,
56
- widths:,
57
- block: RatatuiRuby::Block.new(title: "Processes", borders: [:all])
58
- )
59
-
60
- gauge = RatatuiRuby::Gauge.new(
61
- ratio: @percentage / 100.0,
62
- label: "#{@percentage}%",
63
- style: RatatuiRuby::Style.new(fg: :green),
64
- block: RatatuiRuby::Block.new(title: "Memory Usage", borders: [:all])
65
- )
66
-
67
- layout = RatatuiRuby::Layout.new(
68
- direction: :vertical,
69
- children: [table, gauge],
70
- constraints: [
71
- RatatuiRuby::Constraint.percentage(50),
72
- RatatuiRuby::Constraint.percentage(50),
73
- ]
74
- )
75
-
76
- RatatuiRuby.draw(layout)
77
- end
78
-
79
- def handle_input
80
- event = RatatuiRuby.poll_event
81
- if event
82
- case event[:code]
83
- when "q"
84
- :quit
85
- when "up"
86
- @percentage = [@percentage + 5, 100].min
87
- when "down"
88
- @percentage = [@percentage - 5, 0].max
89
- end
90
- end
91
- end
92
- end
93
-
94
- SystemMonitorApp.new.run if __FILE__ == $0