ratatui_ruby 1.3.0 → 1.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 (263) hide show
  1. checksums.yaml +4 -4
  2. data/ext/ratatui_ruby/Cargo.lock +2 -1
  3. data/ext/ratatui_ruby/Cargo.toml +2 -1
  4. data/ext/ratatui_ruby/src/events.rs +157 -18
  5. data/lib/ratatui_ruby/test_helper/snapshot.rb +58 -10
  6. data/lib/ratatui_ruby/test_helper/subprocess_timeout.rb +35 -0
  7. data/lib/ratatui_ruby/test_helper.rb +2 -0
  8. data/lib/ratatui_ruby/version.rb +1 -1
  9. metadata +17 -270
  10. data/.builds/ruby-3.2.yml +0 -54
  11. data/.builds/ruby-3.3.yml +0 -54
  12. data/.builds/ruby-3.4.yml +0 -54
  13. data/.builds/ruby-4.0.0.yml +0 -54
  14. data/.pre-commit-config.yaml +0 -16
  15. data/.rubocop.yml +0 -10
  16. data/AGENTS.md +0 -147
  17. data/CHANGELOG.md +0 -771
  18. data/README.md +0 -187
  19. data/README.rdoc +0 -302
  20. data/Rakefile +0 -11
  21. data/Steepfile +0 -50
  22. data/doc/concepts/application_architecture.md +0 -321
  23. data/doc/concepts/application_testing.md +0 -193
  24. data/doc/concepts/async.md +0 -190
  25. data/doc/concepts/custom_widgets.md +0 -247
  26. data/doc/concepts/debugging.md +0 -401
  27. data/doc/concepts/event_handling.md +0 -162
  28. data/doc/concepts/interactive_design.md +0 -146
  29. data/doc/contributors/auditing/parity.md +0 -239
  30. data/doc/contributors/design/ruby_frontend.md +0 -448
  31. data/doc/contributors/design/rust_backend.md +0 -434
  32. data/doc/contributors/design.md +0 -11
  33. data/doc/contributors/developing_examples.md +0 -400
  34. data/doc/contributors/documentation_style.md +0 -121
  35. data/doc/contributors/index.md +0 -21
  36. data/doc/contributors/releasing.md +0 -215
  37. data/doc/contributors/todo/align/api_completeness_audit-finished.md +0 -381
  38. data/doc/contributors/todo/align/api_completeness_audit-unfinished.md +0 -200
  39. data/doc/contributors/todo/align/term.md +0 -351
  40. data/doc/contributors/todo/align/terminal.md +0 -647
  41. data/doc/contributors/todo/future_work.md +0 -169
  42. data/doc/contributors/upstream_requests/paragraph_span_rects.md +0 -259
  43. data/doc/contributors/upstream_requests/tab_rects.md +0 -173
  44. data/doc/contributors/upstream_requests/title_rects.md +0 -132
  45. data/doc/custom.css +0 -22
  46. data/doc/getting_started/quickstart.md +0 -291
  47. data/doc/getting_started/why.md +0 -93
  48. data/doc/images/app_all_events.png +0 -0
  49. data/doc/images/app_cli_rich_moments.gif +0 -0
  50. data/doc/images/app_color_picker.png +0 -0
  51. data/doc/images/app_debugging_showcase.gif +0 -0
  52. data/doc/images/app_debugging_showcase.png +0 -0
  53. data/doc/images/app_external_editor.gif +0 -0
  54. data/doc/images/app_login_form.png +0 -0
  55. data/doc/images/app_stateful_interaction.png +0 -0
  56. data/doc/images/verify_quickstart_dsl.png +0 -0
  57. data/doc/images/verify_quickstart_layout.png +0 -0
  58. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  59. data/doc/images/verify_readme_usage.png +0 -0
  60. data/doc/images/widget_barchart.png +0 -0
  61. data/doc/images/widget_block.png +0 -0
  62. data/doc/images/widget_box.png +0 -0
  63. data/doc/images/widget_calendar.png +0 -0
  64. data/doc/images/widget_canvas.png +0 -0
  65. data/doc/images/widget_cell.png +0 -0
  66. data/doc/images/widget_center.png +0 -0
  67. data/doc/images/widget_chart.png +0 -0
  68. data/doc/images/widget_gauge.png +0 -0
  69. data/doc/images/widget_layout_split.png +0 -0
  70. data/doc/images/widget_line_gauge.png +0 -0
  71. data/doc/images/widget_list.png +0 -0
  72. data/doc/images/widget_map.png +0 -0
  73. data/doc/images/widget_overlay.png +0 -0
  74. data/doc/images/widget_popup.png +0 -0
  75. data/doc/images/widget_ratatui_logo.png +0 -0
  76. data/doc/images/widget_ratatui_mascot.png +0 -0
  77. data/doc/images/widget_rect.png +0 -0
  78. data/doc/images/widget_render.png +0 -0
  79. data/doc/images/widget_rich_text.png +0 -0
  80. data/doc/images/widget_scroll_text.png +0 -0
  81. data/doc/images/widget_scrollbar.png +0 -0
  82. data/doc/images/widget_sparkline.png +0 -0
  83. data/doc/images/widget_style_colors.png +0 -0
  84. data/doc/images/widget_table.png +0 -0
  85. data/doc/images/widget_tabs.png +0 -0
  86. data/doc/images/widget_text_width.png +0 -0
  87. data/doc/index.md +0 -34
  88. data/doc/troubleshooting/async.md +0 -4
  89. data/doc/troubleshooting/terminal_limitations.md +0 -131
  90. data/doc/troubleshooting/tui_output.md +0 -197
  91. data/examples/app_all_events/README.md +0 -114
  92. data/examples/app_all_events/app.rb +0 -98
  93. data/examples/app_all_events/model/app_model.rb +0 -159
  94. data/examples/app_all_events/model/event_color_cycle.rb +0 -43
  95. data/examples/app_all_events/model/event_entry.rb +0 -94
  96. data/examples/app_all_events/model/msg.rb +0 -39
  97. data/examples/app_all_events/model/timestamp.rb +0 -56
  98. data/examples/app_all_events/update.rb +0 -75
  99. data/examples/app_all_events/view/app_view.rb +0 -80
  100. data/examples/app_all_events/view/controls_view.rb +0 -54
  101. data/examples/app_all_events/view/counts_view.rb +0 -61
  102. data/examples/app_all_events/view/live_view.rb +0 -72
  103. data/examples/app_all_events/view/log_view.rb +0 -57
  104. data/examples/app_all_events/view.rb +0 -9
  105. data/examples/app_cli_rich_moments/README.md +0 -81
  106. data/examples/app_cli_rich_moments/app.rb +0 -189
  107. data/examples/app_color_picker/README.md +0 -156
  108. data/examples/app_color_picker/app.rb +0 -76
  109. data/examples/app_color_picker/clipboard.rb +0 -86
  110. data/examples/app_color_picker/color.rb +0 -193
  111. data/examples/app_color_picker/controls.rb +0 -92
  112. data/examples/app_color_picker/copy_dialog.rb +0 -168
  113. data/examples/app_color_picker/export_pane.rb +0 -128
  114. data/examples/app_color_picker/harmony.rb +0 -58
  115. data/examples/app_color_picker/input.rb +0 -176
  116. data/examples/app_color_picker/main_container.rb +0 -180
  117. data/examples/app_color_picker/palette.rb +0 -111
  118. data/examples/app_debugging_showcase/README.md +0 -119
  119. data/examples/app_debugging_showcase/app.rb +0 -318
  120. data/examples/app_external_editor/README.md +0 -62
  121. data/examples/app_external_editor/app.rb +0 -344
  122. data/examples/app_login_form/README.md +0 -58
  123. data/examples/app_login_form/app.rb +0 -109
  124. data/examples/app_stateful_interaction/README.md +0 -35
  125. data/examples/app_stateful_interaction/app.rb +0 -328
  126. data/examples/timeout_demo.rb +0 -45
  127. data/examples/verify_quickstart_dsl/README.md +0 -55
  128. data/examples/verify_quickstart_dsl/app.rb +0 -49
  129. data/examples/verify_quickstart_layout/README.md +0 -77
  130. data/examples/verify_quickstart_layout/app.rb +0 -73
  131. data/examples/verify_quickstart_lifecycle/README.md +0 -68
  132. data/examples/verify_quickstart_lifecycle/app.rb +0 -62
  133. data/examples/verify_readme_usage/README.md +0 -49
  134. data/examples/verify_readme_usage/app.rb +0 -42
  135. data/examples/verify_website_managed/README.md +0 -48
  136. data/examples/verify_website_managed/app.rb +0 -36
  137. data/examples/verify_website_menu/README.md +0 -60
  138. data/examples/verify_website_menu/app.rb +0 -84
  139. data/examples/verify_website_spinner/README.md +0 -44
  140. data/examples/verify_website_spinner/app.rb +0 -34
  141. data/examples/widget_barchart/README.md +0 -58
  142. data/examples/widget_barchart/app.rb +0 -240
  143. data/examples/widget_block/README.md +0 -44
  144. data/examples/widget_block/app.rb +0 -258
  145. data/examples/widget_box/README.md +0 -54
  146. data/examples/widget_box/app.rb +0 -255
  147. data/examples/widget_calendar/README.md +0 -48
  148. data/examples/widget_calendar/app.rb +0 -115
  149. data/examples/widget_canvas/README.md +0 -31
  150. data/examples/widget_canvas/app.rb +0 -130
  151. data/examples/widget_cell/README.md +0 -45
  152. data/examples/widget_cell/app.rb +0 -112
  153. data/examples/widget_center/README.md +0 -33
  154. data/examples/widget_center/app.rb +0 -118
  155. data/examples/widget_chart/README.md +0 -50
  156. data/examples/widget_chart/app.rb +0 -220
  157. data/examples/widget_gauge/README.md +0 -50
  158. data/examples/widget_gauge/app.rb +0 -229
  159. data/examples/widget_layout_split/README.md +0 -53
  160. data/examples/widget_layout_split/app.rb +0 -260
  161. data/examples/widget_line_gauge/README.md +0 -50
  162. data/examples/widget_line_gauge/app.rb +0 -219
  163. data/examples/widget_list/README.md +0 -58
  164. data/examples/widget_list/app.rb +0 -382
  165. data/examples/widget_map/README.md +0 -48
  166. data/examples/widget_map/app.rb +0 -95
  167. data/examples/widget_overlay/README.md +0 -45
  168. data/examples/widget_overlay/app.rb +0 -250
  169. data/examples/widget_popup/README.md +0 -45
  170. data/examples/widget_popup/app.rb +0 -106
  171. data/examples/widget_ratatui_logo/README.md +0 -43
  172. data/examples/widget_ratatui_logo/app.rb +0 -104
  173. data/examples/widget_ratatui_mascot/README.md +0 -43
  174. data/examples/widget_ratatui_mascot/app.rb +0 -95
  175. data/examples/widget_rect/README.md +0 -53
  176. data/examples/widget_rect/app.rb +0 -222
  177. data/examples/widget_render/README.md +0 -46
  178. data/examples/widget_render/app.rb +0 -186
  179. data/examples/widget_render/app.rbs +0 -41
  180. data/examples/widget_rich_text/README.md +0 -44
  181. data/examples/widget_rich_text/app.rb +0 -193
  182. data/examples/widget_scroll_text/README.md +0 -46
  183. data/examples/widget_scroll_text/app.rb +0 -109
  184. data/examples/widget_scrollbar/README.md +0 -46
  185. data/examples/widget_scrollbar/app.rb +0 -155
  186. data/examples/widget_sparkline/README.md +0 -51
  187. data/examples/widget_sparkline/app.rb +0 -277
  188. data/examples/widget_style_colors/README.md +0 -43
  189. data/examples/widget_style_colors/app.rb +0 -83
  190. data/examples/widget_table/README.md +0 -57
  191. data/examples/widget_table/app.rb +0 -285
  192. data/examples/widget_tabs/README.md +0 -50
  193. data/examples/widget_tabs/app.rb +0 -183
  194. data/examples/widget_text_width/README.md +0 -44
  195. data/examples/widget_text_width/app.rb +0 -117
  196. data/migrate_to_buffer.rb +0 -145
  197. data/mise.toml +0 -8
  198. data/tasks/autodoc/examples.rb +0 -87
  199. data/tasks/autodoc/member.rb +0 -58
  200. data/tasks/autodoc/name.rb +0 -21
  201. data/tasks/autodoc.rake +0 -21
  202. data/tasks/bump/bump_workflow.rb +0 -49
  203. data/tasks/bump/cargo_lockfile.rb +0 -21
  204. data/tasks/bump/changelog.rb +0 -104
  205. data/tasks/bump/header.rb +0 -32
  206. data/tasks/bump/history.rb +0 -32
  207. data/tasks/bump/links.rb +0 -69
  208. data/tasks/bump/manifest.rb +0 -33
  209. data/tasks/bump/patch_release.rb +0 -19
  210. data/tasks/bump/release_branch.rb +0 -17
  211. data/tasks/bump/release_from_trunk.rb +0 -49
  212. data/tasks/bump/repository.rb +0 -54
  213. data/tasks/bump/ruby_gem.rb +0 -29
  214. data/tasks/bump/sem_ver.rb +0 -44
  215. data/tasks/bump/unreleased_section.rb +0 -73
  216. data/tasks/bump.rake +0 -61
  217. data/tasks/doc/documentation.rb +0 -59
  218. data/tasks/doc/link/file_url.rb +0 -30
  219. data/tasks/doc/link/relative_path.rb +0 -61
  220. data/tasks/doc/link/web_url.rb +0 -55
  221. data/tasks/doc/link.rb +0 -52
  222. data/tasks/doc/link_audit.rb +0 -116
  223. data/tasks/doc/problem.rb +0 -40
  224. data/tasks/doc/source_file.rb +0 -93
  225. data/tasks/doc.rake +0 -905
  226. data/tasks/example_viewer.html.erb +0 -172
  227. data/tasks/extension.rake +0 -14
  228. data/tasks/license/headers_md.rb +0 -223
  229. data/tasks/license/headers_rb.rb +0 -210
  230. data/tasks/license/license_utils.rb +0 -130
  231. data/tasks/license/snippets_md.rb +0 -315
  232. data/tasks/license/snippets_rdoc.rb +0 -150
  233. data/tasks/license.rake +0 -91
  234. data/tasks/lint.rake +0 -170
  235. data/tasks/rbs_predicates/predicate_catalog.rb +0 -52
  236. data/tasks/rbs_predicates/predicate_tests.rb +0 -124
  237. data/tasks/rbs_predicates/rbs_signature.rb +0 -63
  238. data/tasks/rbs_predicates.rake +0 -31
  239. data/tasks/rdoc_config.rb +0 -29
  240. data/tasks/resources/build.yml.erb +0 -60
  241. data/tasks/resources/index.html.erb +0 -141
  242. data/tasks/resources/rubies.yml +0 -7
  243. data/tasks/sourcehut.rake +0 -122
  244. data/tasks/steep.rake +0 -11
  245. data/tasks/terminal_preview/app_screenshot.rb +0 -45
  246. data/tasks/terminal_preview/crash_report.rb +0 -54
  247. data/tasks/terminal_preview/example_app.rb +0 -27
  248. data/tasks/terminal_preview/launcher_script.rb +0 -48
  249. data/tasks/terminal_preview/preview_collection.rb +0 -60
  250. data/tasks/terminal_preview/preview_timing.rb +0 -24
  251. data/tasks/terminal_preview/safety_confirmation.rb +0 -58
  252. data/tasks/terminal_preview/saved_screenshot.rb +0 -56
  253. data/tasks/terminal_preview/system_appearance.rb +0 -13
  254. data/tasks/terminal_preview/terminal_window.rb +0 -138
  255. data/tasks/terminal_preview/window_id.rb +0 -16
  256. data/tasks/terminal_preview.rake +0 -30
  257. data/tasks/test.rake +0 -36
  258. data/tasks/website/index_page.rb +0 -30
  259. data/tasks/website/version.rb +0 -122
  260. data/tasks/website/version_menu.rb +0 -68
  261. data/tasks/website/versioned_documentation.rb +0 -83
  262. data/tasks/website/website.rb +0 -53
  263. data/tasks/website.rake +0 -28
@@ -1,155 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: MIT-0
6
- #++
7
-
8
- $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
9
- require "ratatui_ruby"
10
-
11
- # Demonstrates viewport navigation with interactive theme and orientation cycling.
12
- #
13
- # Content overflows. Users get lost in long lists without landmarks. They need to know where they are and how much is left.
14
- #
15
- # This demo showcases the <tt>Scrollbar</tt> widget. It provides an interactive playground where you can toggle orientations and cycle through different themes (Standard, Rounded, ASCII, Minimal) in real-time.
16
- #
17
- # Use it to understand how to provide spatial awareness and navigation cues for overflowing content.
18
- #
19
- # === Example
20
- #
21
- # Run the demo from the terminal:
22
- #
23
- # ruby examples/widget_scrollbar/app.rb
24
- #
25
- # rdoc-image:/doc/images/widget_scrollbar.png
26
- class WidgetScrollbar
27
- def initialize
28
- @scroll_position = 0
29
- @content_length = 50
30
- @lines = (1..@content_length).map { |i| "Line #{i}" }
31
- @orientation_index = 0
32
- @orientations = [
33
- :vertical,
34
- :vertical_right,
35
- :vertical_left,
36
- :horizontal,
37
- :horizontal_bottom,
38
- :horizontal_top,
39
- ]
40
- @theme_index = 0
41
- @themes = [
42
- {
43
- name: "Standard",
44
- track_symbol: nil,
45
- thumb_symbol: "█",
46
- track_style: nil,
47
- thumb_style: nil,
48
- begin_symbol: nil,
49
- end_symbol: nil,
50
- },
51
- {
52
- name: "Rounded",
53
- track_symbol: "│",
54
- thumb_symbol: "┃",
55
- track_style: { fg: "dark_gray" },
56
- thumb_style: { fg: "cyan" },
57
- begin_symbol: "▲",
58
- end_symbol: "▼",
59
- },
60
- {
61
- name: "ASCII",
62
- track_symbol: "|",
63
- thumb_symbol: "#",
64
- track_style: { fg: "white" },
65
- thumb_style: { fg: "red" },
66
- begin_symbol: "^",
67
- end_symbol: "v",
68
- },
69
- {
70
- name: "Minimal",
71
- track_symbol: " ",
72
- thumb_symbol: "▐",
73
- track_style: nil,
74
- thumb_style: { fg: "yellow" },
75
- begin_symbol: nil,
76
- end_symbol: nil,
77
- },
78
- ]
79
- end
80
-
81
- def run
82
- RatatuiRuby.run do |tui|
83
- @tui = tui
84
- loop do
85
- draw
86
- event = @tui.poll_event
87
- break if event == "q" || event == :ctrl_c
88
-
89
- handle_event(event)
90
- end
91
- end
92
- end
93
-
94
- private def handle_event(event)
95
- if event.mouse?
96
- case event.kind
97
- when "scroll_up"
98
- @scroll_position = [@scroll_position - 1, 0].max
99
- when "scroll_down"
100
- @scroll_position = [@scroll_position + 1, @content_length].min
101
- end
102
- end
103
-
104
- if event.key? && event.to_s == "s"
105
- @theme_index = (@theme_index + 1) % @themes.length
106
- end
107
-
108
- if event.key? && event.to_s == "o"
109
- @orientation_index = (@orientation_index + 1) % @orientations.length
110
- end
111
- end
112
-
113
- private def draw
114
- @tui.draw do |frame|
115
- # Calculate visible lines based on scroll position
116
- # In a real app, you'd want to know the height of the available area.
117
- # For this demo, we'll just show all lines but offset the text.
118
- visible_lines = @lines[@scroll_position..-1] || []
119
-
120
- # Paragraph with content
121
- theme = @themes[@theme_index]
122
- orientation = @orientations[@orientation_index]
123
-
124
- p = @tui.paragraph(
125
- text: visible_lines.join("\n"),
126
- block: @tui.block(
127
- titles: [
128
- { content: "Scroll with Mouse Wheel | Theme: #{theme[:name]} | Orientation: #{orientation}" },
129
- { content: "Press 's' to cycle theme, 'o' to cycle orientation", position: :bottom, alignment: :center },
130
- ],
131
- borders: [:all]
132
- )
133
- )
134
-
135
- # Scrollbar
136
- s = @tui.scrollbar(
137
- content_length: @content_length,
138
- position: @scroll_position,
139
- orientation:,
140
- track_symbol: theme[:track_symbol],
141
- thumb_symbol: theme[:thumb_symbol],
142
- track_style: theme[:track_style],
143
- thumb_style: theme[:thumb_style],
144
- begin_symbol: theme[:begin_symbol],
145
- end_symbol: theme[:end_symbol]
146
- )
147
-
148
- # Render paragraph first, then scrollbar on top
149
- frame.render_widget(p, frame.area)
150
- frame.render_widget(s, frame.area)
151
- end
152
- end
153
- end
154
-
155
- WidgetScrollbar.new.run if __FILE__ == $PROGRAM_NAME
@@ -1,51 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
-
6
- # Sparkline Widget Example
7
-
8
- [![widget_sparkline](../../doc/images/widget_sparkline.png)](app.rb)
9
-
10
- Demonstrates high-density data visualization in a condensed footprint.
11
-
12
- Users need context. A single number ("90% CPU") tells you status, but not the trend. Full charts take up too much space. Sparklines condense history into a single line, perfect for headers and dashboards.
13
-
14
- ## Features Demonstrated
15
-
16
- - **High Density**: Showing dozens of data points in a small area.
17
- - **Direction**: Rendering Left-to-Right (standard) or Right-to-Left (like a scrolling ticker).
18
- - **Gaps**: Handling `nil` values with "absent symbols" to indicate missing data.
19
- - **Styling**: Using colors and custom characters to indicate severity or type.
20
-
21
- ## Hotkeys
22
-
23
- - **Up/Down (↑/↓)**: Cycle Data Set (`data`)
24
- - **d**: Cycle Direction (`direction`)
25
- - **c**: Cycle Color (`style`)
26
- - **m**: Cycle Absent Value Marker Symbol (`absent_value_symbol`)
27
- - **s**: Cycle Absent Value Marker Style (`absent_value_style`)
28
- - **b**: Cycle Bar Character Set (`bar_set`)
29
- - **q**: Quit
30
-
31
- ## Usage
32
-
33
- <!-- SPDX-SnippetBegin -->
34
- <!--
35
- SPDX-FileCopyrightText: 2026 Kerrick Long
36
- SPDX-License-Identifier: MIT-0
37
- -->
38
- ```bash
39
- ruby examples/widget_sparkline/app.rb
40
- ```
41
- <!-- SPDX-SnippetEnd -->
42
-
43
- ## Learning Outcomes
44
-
45
- Use this example if you need to...
46
-
47
- - Add a "CPU Load" graph to your header.
48
- - Visualize stock price trends in a list row.
49
- - Monitor memory usage over the last 60 seconds.
50
-
51
- [Read the source code →](app.rb)
@@ -1,277 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: MIT-0
6
- #++
7
-
8
- $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
9
- require "ratatui_ruby"
10
-
11
- # Demonstrates high-density data visualization with interactive attribute cycling.
12
- #
13
- # Users need context. A single value ("90% CPU") tells you current status, but not the trend. Full charts take up too much room.
14
- #
15
- # This demo showcases the <tt>Sparkline</tt> widget. It provides an interactive playground where you can cycle through data sets, directions, colors, and custom bar sets.
16
- #
17
- # Use it to understand how to condense history into a single line for dashboards or headers.
18
- #
19
- # === Example
20
- #
21
- # Run the demo from the terminal:
22
- #
23
- # ruby examples/widget_sparkline/app.rb
24
- #
25
- # rdoc-image:/doc/images/widget_sparkline.png
26
- class WidgetSparkline
27
- def run
28
- RatatuiRuby.run do |tui|
29
- @tui = tui
30
- setup
31
- loop do
32
- render
33
- break if handle_input == :quit
34
- end
35
- end
36
- end
37
-
38
- private def setup
39
- # Data sets with different characteristics
40
- @data_sets = [
41
- {
42
- name: "Steady Growth",
43
- data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
44
- },
45
- {
46
- name: "With Gaps",
47
- data: [5, nil, 8, nil, 6, nil, 9, nil, 7, nil, 10, nil],
48
- },
49
- {
50
- name: "Random",
51
- data: [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8],
52
- },
53
- {
54
- name: "Sawtooth",
55
- data: [1, 2, 3, 4, 5, 4, 3, 2, 1, 2, 3, 4],
56
- },
57
- {
58
- name: "Peaks",
59
- data: [1, 5, 1, 8, 1, 6, 1, 9, 1, 7, 1, 10],
60
- },
61
- ]
62
- @data_index = 2
63
- srand(12345) # Ensure reproducible "Random" data for snapshots
64
-
65
- @directions = [
66
- { name: "Left to Right", direction: :left_to_right },
67
- { name: "Right to Left", direction: :right_to_left },
68
- ]
69
- @direction_index = 0
70
-
71
- @styles = [
72
- { name: "Green", style: @tui.style(fg: :green) },
73
- { name: "Yellow", style: @tui.style(fg: :yellow) },
74
- { name: "Red", style: @tui.style(fg: :red) },
75
- { name: "Cyan", style: @tui.style(fg: :cyan) },
76
- { name: "Magenta", style: @tui.style(fg: :magenta) },
77
- ]
78
- @style_index = 3
79
-
80
- @absent_symbols = [
81
- { name: "None", symbol: nil },
82
- { name: "Dot (·)", symbol: "·" },
83
- { name: "Square (▫)", symbol: "▫" },
84
- { name: "Dash (-)", symbol: "-" },
85
- { name: "Underscore (_)", symbol: "_" },
86
- ]
87
- @absent_symbol_index = 1
88
-
89
- @absent_styles = [
90
- { name: "Default", style: nil },
91
- { name: "Dark Gray", style: @tui.style(fg: :dark_gray) },
92
- { name: "Dim Red", style: @tui.style(fg: :red, modifiers: [:dim]) },
93
- { name: "Dim Yellow", style: @tui.style(fg: :yellow, modifiers: [:dim]) },
94
- ]
95
- @absent_style_index = 2
96
-
97
- @bar_sets = [
98
- { name: "Default (Block)", set: nil },
99
- {
100
- name: "Numbers (0-8)",
101
- set: {
102
- 0 => "0", 1 => "1", 2 => "2", 3 => "3", 4 => "4", 5 => "5", 6 => "6", 7 => "7", 8 => "8"
103
- },
104
- },
105
- { name: "ASCII (Heights)", set: [" ", "_", ".", "-", "=", "+", "*", "#", "@"] },
106
- ]
107
- @bar_set_index = 0
108
-
109
- @hotkey_style = @tui.style(modifiers: [:bold, :underlined])
110
- end
111
-
112
- private def render
113
- @tui.draw do |frame|
114
- data_set = @data_sets[@data_index]
115
- direction = @directions[@direction_index][:direction]
116
- style = @styles[@style_index][:style]
117
- absent_symbol = @absent_symbols[@absent_symbol_index][:symbol]
118
- absent_value_style = @absent_styles[@absent_style_index][:style]
119
- bar_set = @bar_sets[@bar_set_index][:set]
120
-
121
- # Use static data for clarity when cycling options
122
- current_data = data_set[:data]
123
-
124
- layout = @tui.layout_split(
125
- frame.area,
126
- direction: :vertical,
127
- constraints: [
128
- @tui.constraint_fill(1),
129
- @tui.constraint_length(6),
130
- ]
131
- )
132
-
133
- # Main content area with multiple sparkline examples
134
- main_content_area = layout[0]
135
- main_layout = @tui.layout_split(
136
- main_content_area,
137
- direction: :vertical,
138
- constraints: [
139
- @tui.constraint_length(1),
140
- @tui.constraint_length(3),
141
- @tui.constraint_length(3),
142
- @tui.constraint_length(3),
143
- @tui.constraint_length(3),
144
- @tui.constraint_fill(1),
145
- ]
146
- )
147
-
148
- frame.render_widget(
149
- @tui.paragraph(text: "Sparkline Widget - Cycle attributes with hotkeys"),
150
- main_layout[0]
151
- )
152
-
153
- # Sparkline 1: Main interactive sparkline
154
- frame.render_widget(
155
- @tui.sparkline(
156
- data: current_data,
157
- direction:,
158
- style:,
159
- absent_value_symbol: absent_symbol,
160
- absent_value_style:,
161
- bar_set:,
162
- block: @tui.block(title: "Interactive Sparkline")
163
- ),
164
- main_layout[1]
165
- )
166
-
167
- # Sparkline 2: Same data, opposite direction
168
- frame.render_widget(
169
- @tui.sparkline(
170
- data: current_data.reverse,
171
- direction:,
172
- style:,
173
- absent_value_symbol: absent_symbol,
174
- absent_value_style:,
175
- bar_set:,
176
- block: @tui.block(title: "Reversed Data")
177
- ),
178
- main_layout[2]
179
- )
180
-
181
- # Sparkline 3: Without absent value symbol (for comparison)
182
- frame.render_widget(
183
- @tui.sparkline(
184
- data: current_data,
185
- direction:,
186
- style:,
187
- bar_set:,
188
- block: @tui.block(title: "Without Absent Marker")
189
- ),
190
- main_layout[3]
191
- )
192
-
193
- # Sparkline 4: Gap pattern responsive to absent marker controls
194
- frame.render_widget(
195
- @tui.sparkline(
196
- data: [5, nil, 8, nil, 6, nil, 9, nil, 7, nil, 10, nil],
197
- direction:,
198
- style: @tui.style(fg: :blue),
199
- absent_value_symbol: absent_symbol,
200
- absent_value_style:,
201
- bar_set:,
202
- block: @tui.block(title: "Gap Pattern (Responsive)")
203
- ),
204
- main_layout[4]
205
- )
206
-
207
- # Bottom control panel
208
- control_area = layout[1]
209
- frame.render_widget(
210
- @tui.block(
211
- title: "Controls",
212
- borders: [:all],
213
- children: [
214
- @tui.paragraph(
215
- text: [
216
- # Line 1: Data
217
- @tui.text_line(spans: [
218
- @tui.text_span(content: "↑/↓", style: @hotkey_style),
219
- @tui.text_span(content: ": Data (#{@data_sets[@data_index][:name]})"),
220
- ]),
221
- # Line 2: View
222
- @tui.text_line(spans: [
223
- @tui.text_span(content: "d", style: @hotkey_style),
224
- @tui.text_span(content: ": Direction (#{@directions[@direction_index][:name]}) "),
225
- @tui.text_span(content: "c", style: @hotkey_style),
226
- @tui.text_span(content: ": Color (#{@styles[@style_index][:name]})"),
227
- ]),
228
- # Line 3: Markers
229
- @tui.text_line(spans: [
230
- @tui.text_span(content: "m", style: @hotkey_style),
231
- @tui.text_span(content: ": Absent Value Symbol (#{@absent_symbols[@absent_symbol_index][:name]}) "),
232
- @tui.text_span(content: "s", style: @hotkey_style),
233
- @tui.text_span(content: ": Absent Value Style (#{@absent_styles[@absent_style_index][:name]})"),
234
- ]),
235
- # Line 4: General
236
- @tui.text_line(spans: [
237
- @tui.text_span(content: "b", style: @hotkey_style),
238
- @tui.text_span(content: ": Bar Set (#{@bar_sets[@bar_set_index][:name]}) "),
239
- @tui.text_span(content: "q", style: @hotkey_style),
240
- @tui.text_span(content: ": Quit"),
241
- ]),
242
- ]
243
- ),
244
- ]
245
- ),
246
- control_area
247
- )
248
- end
249
- end
250
-
251
- private def handle_input
252
- event = @tui.poll_event
253
-
254
- case event
255
- in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
256
- :quit
257
- in type: :key, code: "up"
258
- @data_index = (@data_index - 1) % @data_sets.length
259
- in type: :key, code: "down"
260
- @data_index = (@data_index + 1) % @data_sets.length
261
- in type: :key, code: "d"
262
- @direction_index = (@direction_index + 1) % @directions.length
263
- in type: :key, code: "c"
264
- @style_index = (@style_index + 1) % @styles.length
265
- in type: :key, code: "m"
266
- @absent_symbol_index = (@absent_symbol_index + 1) % @absent_symbols.length
267
- in type: :key, code: "s"
268
- @absent_style_index = (@absent_style_index + 1) % @absent_styles.length
269
- in type: :key, code: "b"
270
- @bar_set_index = (@bar_set_index + 1) % @bar_sets.length
271
- else
272
- nil
273
- end
274
- end
275
- end
276
-
277
- WidgetSparkline.new.run if __FILE__ == $PROGRAM_NAME
@@ -1,43 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
-
6
- # Style Colors Example
7
-
8
- [![widget_style_colors](../../doc/images/widget_style_colors.png)](app.rb)
9
-
10
- Demonstrates high-fidelity color support.
11
-
12
- Terminals support millions of colors. This example generates a mathematically precise HSL gradient to prove the rendering engine's color fidelity.
13
-
14
- ## Features Demonstrated
15
-
16
- - **HSL to RGB Conversion**: generating smooth color gradients programmatically.
17
- - **TrueColor Support**: Rendering arbitrary HEX colors.
18
-
19
- ## Hotkeys
20
-
21
- - **q** / **Ctrl+c**: Quit
22
-
23
- ## Usage
24
-
25
- <!-- SPDX-SnippetBegin -->
26
- <!--
27
- SPDX-FileCopyrightText: 2026 Kerrick Long
28
- SPDX-License-Identifier: MIT-0
29
- -->
30
- ```bash
31
- ruby examples/widget_style_colors/app.rb
32
- ```
33
- <!-- SPDX-SnippetEnd -->
34
-
35
- ## Learning Outcomes
36
-
37
- Use this example if you need to...
38
-
39
- - Create meaningful heatmaps.
40
- - Generate color palettes dynamically.
41
- - Test your terminal's color support capabilities.
42
-
43
- [Read the source code →](app.rb)
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: MIT-0
6
- #++
7
-
8
- $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
9
- require "ratatui_ruby"
10
-
11
- # Demonstrates terminal color rendering and the Color module.
12
- #
13
- # Terminal apps need vibrant colors. Specifying colors as symbols or
14
- # calculated hex strings works but limits expressiveness.
15
- #
16
- # This demo shows the Color module's constructors for creating colors
17
- # from HSL values or hex integers, producing a full-spectrum gradient.
18
- #
19
- # Use it to understand color representation and the Color.hsl/Color.hex APIs.
20
- class WidgetStyleColors
21
- def initialize
22
- @width = 80
23
- @height = 24
24
- end
25
-
26
- def run
27
- RatatuiRuby.run do |tui|
28
- loop do
29
- tui.draw do |frame|
30
- frame.render_widget(render(tui), frame.area)
31
- end
32
- event = tui.poll_event
33
- break if event.key? && (event.ctrl_c? || event == :q)
34
- end
35
- end
36
- end
37
-
38
- private def render(tui)
39
- lines = []
40
-
41
- (0...@height).each do |row|
42
- spans = []
43
- (0...@width).each do |col|
44
- hue = (col.to_f / @width) * 360.0
45
- lightness = 50.0 - ((row.to_f / @height) * 50.0)
46
-
47
- # Use Color.hsl for top half, Color.hsluv for bottom half
48
- # HSLuv provides perceptually uniform colors (same visual brightness)
49
- hex = if row < @height / 2
50
- RatatuiRuby::Style::Color.hsl(hue, 100.0, lightness)
51
- else
52
- # HSLuv: perceptually uniform - all colors appear equal brightness
53
- RatatuiRuby::Style::Color.hsluv(hue, 100.0, lightness)
54
- end
55
-
56
- # Demonstrate Style.with for concise inline styling
57
- span = tui.text_span(
58
- content: " ",
59
- style: RatatuiRuby::Style::Style.with(bg: hex)
60
- )
61
- spans << span
62
- end
63
-
64
- lines << tui.text_line(spans:)
65
- end
66
-
67
- # Also demonstrate Color.hex for the border
68
- border_color = RatatuiRuby::Style::Color.hex(0xFFD700) # Gold
69
-
70
- tui.paragraph(
71
- text: lines,
72
- block: tui.block(
73
- title: "HSL (top) vs HSLuv (bottom) - Style.with demo (Press 'q' to exit)",
74
- borders: [:all],
75
- border_type: :rounded,
76
- # Using Style.with for concise border styling
77
- border_style: RatatuiRuby::Style::Style.with(fg: border_color)
78
- )
79
- )
80
- end
81
- end
82
-
83
- WidgetStyleColors.new.run if __FILE__ == $PROGRAM_NAME
@@ -1,57 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
-
6
- # Table (Row, Cell) Example
7
-
8
- [![widget_table](../../doc/images/widget_table.png)](app.rb)
9
-
10
- Demonstrates advanced options for the `Table` widget, including selection, row-level highlighting, and column-level highlighting.
11
-
12
- Data grids are complex. Users expect to navigate them with keys, select rows, and clearly see which cell is active. The `Table` widget provides these features out of the box efficiently.
13
-
14
- ## Features Demonstrated
15
-
16
- - **Selection State**: Managing `selected_row` and `selected_column` to track user focus.
17
- - **Complex Highlighting**:
18
- - **Row**: Highlight the entire active row.
19
- - **Highlight Symbol:** Adding a visual indicator (like `> `) to the selected row.
20
- - **Spacing:** Adjusting `column_spacing` and `highlight_spacing` to control layout density.
21
- - **Flex Layout:** Switching between different column distribution modes (`legacy`, `start`, `space_between`, etc.).
22
- - **Offset Control:** Manually controlling the scroll position using `offset`.
23
-
24
- ## Hotkeys
25
-
26
- - **Arrows (↑/↓)**: Navigate Rows (`selected_row`)
27
- - **Arrows (←/→)**: Navigate Columns (`selected_column`)
28
- - **x**: Toggle Row Selection (`selected_row` = nil)
29
- - **s**: Cycle Table Style (`style`)
30
- - **p**: Cycle Spacing (`highlight_spacing`)
31
- - **c**: Toggle Column Highlight (`column_highlight_style`)
32
- - **z**: Toggle Cell Highlight (`cell_highlight_style`)
33
- - **o**: Cycle Offset Mode (`offset`)
34
- - **f**: Cycle Flex Mode (`flex`)
35
- - **q**: Quit
36
-
37
- ## Usage
38
-
39
- <!-- SPDX-SnippetBegin -->
40
- <!--
41
- SPDX-FileCopyrightText: 2026 Kerrick Long
42
- SPDX-License-Identifier: MIT-0
43
- -->
44
- ```bash
45
- ruby examples/widget_table/app.rb
46
- ```
47
- <!-- SPDX-SnippetEnd -->
48
-
49
- ## Learning Outcomes
50
-
51
- Use this example if you need to...
52
-
53
- - Build a file explorer or process list.
54
- - Create a data-heavy dashboard.
55
- - Handle conflicting style requirements (e.g., "Highlight this row, but make this error cell red").
56
-
57
- [Read the source code →](app.rb)