ratatui_ruby 1.2.0 → 1.2.2

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 (260) 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/version.rb +1 -1
  6. metadata +1 -255
  7. data/.builds/ruby-3.2.yml +0 -54
  8. data/.builds/ruby-3.3.yml +0 -54
  9. data/.builds/ruby-3.4.yml +0 -54
  10. data/.builds/ruby-4.0.0.yml +0 -54
  11. data/.pre-commit-config.yaml +0 -16
  12. data/.rubocop.yml +0 -10
  13. data/AGENTS.md +0 -147
  14. data/CHANGELOG.md +0 -751
  15. data/README.md +0 -187
  16. data/README.rdoc +0 -302
  17. data/Rakefile +0 -11
  18. data/Steepfile +0 -50
  19. data/doc/concepts/application_architecture.md +0 -321
  20. data/doc/concepts/application_testing.md +0 -193
  21. data/doc/concepts/async.md +0 -190
  22. data/doc/concepts/custom_widgets.md +0 -247
  23. data/doc/concepts/debugging.md +0 -401
  24. data/doc/concepts/event_handling.md +0 -162
  25. data/doc/concepts/interactive_design.md +0 -146
  26. data/doc/contributors/auditing/parity.md +0 -239
  27. data/doc/contributors/design/ruby_frontend.md +0 -448
  28. data/doc/contributors/design/rust_backend.md +0 -434
  29. data/doc/contributors/design.md +0 -11
  30. data/doc/contributors/developing_examples.md +0 -400
  31. data/doc/contributors/documentation_style.md +0 -121
  32. data/doc/contributors/index.md +0 -21
  33. data/doc/contributors/releasing.md +0 -215
  34. data/doc/contributors/todo/align/api_completeness_audit-finished.md +0 -381
  35. data/doc/contributors/todo/align/api_completeness_audit-unfinished.md +0 -200
  36. data/doc/contributors/todo/align/term.md +0 -351
  37. data/doc/contributors/todo/align/terminal.md +0 -647
  38. data/doc/contributors/todo/future_work.md +0 -169
  39. data/doc/contributors/upstream_requests/paragraph_span_rects.md +0 -259
  40. data/doc/contributors/upstream_requests/tab_rects.md +0 -173
  41. data/doc/contributors/upstream_requests/title_rects.md +0 -132
  42. data/doc/custom.css +0 -22
  43. data/doc/getting_started/quickstart.md +0 -291
  44. data/doc/getting_started/why.md +0 -93
  45. data/doc/images/app_all_events.png +0 -0
  46. data/doc/images/app_cli_rich_moments.gif +0 -0
  47. data/doc/images/app_color_picker.png +0 -0
  48. data/doc/images/app_debugging_showcase.gif +0 -0
  49. data/doc/images/app_debugging_showcase.png +0 -0
  50. data/doc/images/app_external_editor.gif +0 -0
  51. data/doc/images/app_login_form.png +0 -0
  52. data/doc/images/app_stateful_interaction.png +0 -0
  53. data/doc/images/verify_quickstart_dsl.png +0 -0
  54. data/doc/images/verify_quickstart_layout.png +0 -0
  55. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  56. data/doc/images/verify_readme_usage.png +0 -0
  57. data/doc/images/widget_barchart.png +0 -0
  58. data/doc/images/widget_block.png +0 -0
  59. data/doc/images/widget_box.png +0 -0
  60. data/doc/images/widget_calendar.png +0 -0
  61. data/doc/images/widget_canvas.png +0 -0
  62. data/doc/images/widget_cell.png +0 -0
  63. data/doc/images/widget_center.png +0 -0
  64. data/doc/images/widget_chart.png +0 -0
  65. data/doc/images/widget_gauge.png +0 -0
  66. data/doc/images/widget_layout_split.png +0 -0
  67. data/doc/images/widget_line_gauge.png +0 -0
  68. data/doc/images/widget_list.png +0 -0
  69. data/doc/images/widget_map.png +0 -0
  70. data/doc/images/widget_overlay.png +0 -0
  71. data/doc/images/widget_popup.png +0 -0
  72. data/doc/images/widget_ratatui_logo.png +0 -0
  73. data/doc/images/widget_ratatui_mascot.png +0 -0
  74. data/doc/images/widget_rect.png +0 -0
  75. data/doc/images/widget_render.png +0 -0
  76. data/doc/images/widget_rich_text.png +0 -0
  77. data/doc/images/widget_scroll_text.png +0 -0
  78. data/doc/images/widget_scrollbar.png +0 -0
  79. data/doc/images/widget_sparkline.png +0 -0
  80. data/doc/images/widget_style_colors.png +0 -0
  81. data/doc/images/widget_table.png +0 -0
  82. data/doc/images/widget_tabs.png +0 -0
  83. data/doc/images/widget_text_width.png +0 -0
  84. data/doc/index.md +0 -34
  85. data/doc/troubleshooting/async.md +0 -4
  86. data/doc/troubleshooting/terminal_limitations.md +0 -131
  87. data/doc/troubleshooting/tui_output.md +0 -197
  88. data/examples/app_all_events/README.md +0 -114
  89. data/examples/app_all_events/app.rb +0 -98
  90. data/examples/app_all_events/model/app_model.rb +0 -159
  91. data/examples/app_all_events/model/event_color_cycle.rb +0 -43
  92. data/examples/app_all_events/model/event_entry.rb +0 -94
  93. data/examples/app_all_events/model/msg.rb +0 -39
  94. data/examples/app_all_events/model/timestamp.rb +0 -56
  95. data/examples/app_all_events/update.rb +0 -75
  96. data/examples/app_all_events/view/app_view.rb +0 -80
  97. data/examples/app_all_events/view/controls_view.rb +0 -54
  98. data/examples/app_all_events/view/counts_view.rb +0 -61
  99. data/examples/app_all_events/view/live_view.rb +0 -72
  100. data/examples/app_all_events/view/log_view.rb +0 -57
  101. data/examples/app_all_events/view.rb +0 -9
  102. data/examples/app_cli_rich_moments/README.md +0 -81
  103. data/examples/app_cli_rich_moments/app.rb +0 -189
  104. data/examples/app_color_picker/README.md +0 -156
  105. data/examples/app_color_picker/app.rb +0 -76
  106. data/examples/app_color_picker/clipboard.rb +0 -86
  107. data/examples/app_color_picker/color.rb +0 -193
  108. data/examples/app_color_picker/controls.rb +0 -92
  109. data/examples/app_color_picker/copy_dialog.rb +0 -168
  110. data/examples/app_color_picker/export_pane.rb +0 -128
  111. data/examples/app_color_picker/harmony.rb +0 -58
  112. data/examples/app_color_picker/input.rb +0 -176
  113. data/examples/app_color_picker/main_container.rb +0 -180
  114. data/examples/app_color_picker/palette.rb +0 -111
  115. data/examples/app_debugging_showcase/README.md +0 -119
  116. data/examples/app_debugging_showcase/app.rb +0 -318
  117. data/examples/app_external_editor/README.md +0 -62
  118. data/examples/app_external_editor/app.rb +0 -344
  119. data/examples/app_login_form/README.md +0 -58
  120. data/examples/app_login_form/app.rb +0 -109
  121. data/examples/app_stateful_interaction/README.md +0 -35
  122. data/examples/app_stateful_interaction/app.rb +0 -328
  123. data/examples/timeout_demo.rb +0 -45
  124. data/examples/verify_quickstart_dsl/README.md +0 -55
  125. data/examples/verify_quickstart_dsl/app.rb +0 -49
  126. data/examples/verify_quickstart_layout/README.md +0 -77
  127. data/examples/verify_quickstart_layout/app.rb +0 -73
  128. data/examples/verify_quickstart_lifecycle/README.md +0 -68
  129. data/examples/verify_quickstart_lifecycle/app.rb +0 -62
  130. data/examples/verify_readme_usage/README.md +0 -49
  131. data/examples/verify_readme_usage/app.rb +0 -42
  132. data/examples/verify_website_managed/README.md +0 -48
  133. data/examples/verify_website_managed/app.rb +0 -36
  134. data/examples/verify_website_menu/README.md +0 -60
  135. data/examples/verify_website_menu/app.rb +0 -84
  136. data/examples/verify_website_spinner/README.md +0 -44
  137. data/examples/verify_website_spinner/app.rb +0 -34
  138. data/examples/widget_barchart/README.md +0 -58
  139. data/examples/widget_barchart/app.rb +0 -240
  140. data/examples/widget_block/README.md +0 -44
  141. data/examples/widget_block/app.rb +0 -258
  142. data/examples/widget_box/README.md +0 -54
  143. data/examples/widget_box/app.rb +0 -255
  144. data/examples/widget_calendar/README.md +0 -48
  145. data/examples/widget_calendar/app.rb +0 -115
  146. data/examples/widget_canvas/README.md +0 -31
  147. data/examples/widget_canvas/app.rb +0 -130
  148. data/examples/widget_cell/README.md +0 -45
  149. data/examples/widget_cell/app.rb +0 -112
  150. data/examples/widget_center/README.md +0 -33
  151. data/examples/widget_center/app.rb +0 -118
  152. data/examples/widget_chart/README.md +0 -50
  153. data/examples/widget_chart/app.rb +0 -220
  154. data/examples/widget_gauge/README.md +0 -50
  155. data/examples/widget_gauge/app.rb +0 -229
  156. data/examples/widget_layout_split/README.md +0 -53
  157. data/examples/widget_layout_split/app.rb +0 -260
  158. data/examples/widget_line_gauge/README.md +0 -50
  159. data/examples/widget_line_gauge/app.rb +0 -219
  160. data/examples/widget_list/README.md +0 -58
  161. data/examples/widget_list/app.rb +0 -382
  162. data/examples/widget_map/README.md +0 -48
  163. data/examples/widget_map/app.rb +0 -95
  164. data/examples/widget_overlay/README.md +0 -45
  165. data/examples/widget_overlay/app.rb +0 -250
  166. data/examples/widget_popup/README.md +0 -45
  167. data/examples/widget_popup/app.rb +0 -106
  168. data/examples/widget_ratatui_logo/README.md +0 -43
  169. data/examples/widget_ratatui_logo/app.rb +0 -104
  170. data/examples/widget_ratatui_mascot/README.md +0 -43
  171. data/examples/widget_ratatui_mascot/app.rb +0 -95
  172. data/examples/widget_rect/README.md +0 -53
  173. data/examples/widget_rect/app.rb +0 -222
  174. data/examples/widget_render/README.md +0 -46
  175. data/examples/widget_render/app.rb +0 -186
  176. data/examples/widget_render/app.rbs +0 -41
  177. data/examples/widget_rich_text/README.md +0 -44
  178. data/examples/widget_rich_text/app.rb +0 -193
  179. data/examples/widget_scroll_text/README.md +0 -46
  180. data/examples/widget_scroll_text/app.rb +0 -109
  181. data/examples/widget_scrollbar/README.md +0 -46
  182. data/examples/widget_scrollbar/app.rb +0 -155
  183. data/examples/widget_sparkline/README.md +0 -51
  184. data/examples/widget_sparkline/app.rb +0 -277
  185. data/examples/widget_style_colors/README.md +0 -43
  186. data/examples/widget_style_colors/app.rb +0 -83
  187. data/examples/widget_table/README.md +0 -57
  188. data/examples/widget_table/app.rb +0 -285
  189. data/examples/widget_tabs/README.md +0 -50
  190. data/examples/widget_tabs/app.rb +0 -183
  191. data/examples/widget_text_width/README.md +0 -44
  192. data/examples/widget_text_width/app.rb +0 -117
  193. data/migrate_to_buffer.rb +0 -145
  194. data/mise.toml +0 -8
  195. data/tasks/autodoc/examples.rb +0 -87
  196. data/tasks/autodoc/member.rb +0 -58
  197. data/tasks/autodoc/name.rb +0 -21
  198. data/tasks/autodoc.rake +0 -21
  199. data/tasks/bump/bump_workflow.rb +0 -49
  200. data/tasks/bump/cargo_lockfile.rb +0 -21
  201. data/tasks/bump/changelog.rb +0 -104
  202. data/tasks/bump/header.rb +0 -32
  203. data/tasks/bump/history.rb +0 -32
  204. data/tasks/bump/links.rb +0 -69
  205. data/tasks/bump/manifest.rb +0 -33
  206. data/tasks/bump/patch_release.rb +0 -19
  207. data/tasks/bump/release_branch.rb +0 -17
  208. data/tasks/bump/release_from_trunk.rb +0 -49
  209. data/tasks/bump/repository.rb +0 -54
  210. data/tasks/bump/ruby_gem.rb +0 -29
  211. data/tasks/bump/sem_ver.rb +0 -44
  212. data/tasks/bump/unreleased_section.rb +0 -73
  213. data/tasks/bump.rake +0 -61
  214. data/tasks/doc/documentation.rb +0 -59
  215. data/tasks/doc/link/file_url.rb +0 -30
  216. data/tasks/doc/link/relative_path.rb +0 -61
  217. data/tasks/doc/link/web_url.rb +0 -55
  218. data/tasks/doc/link.rb +0 -52
  219. data/tasks/doc/link_audit.rb +0 -116
  220. data/tasks/doc/problem.rb +0 -40
  221. data/tasks/doc/source_file.rb +0 -93
  222. data/tasks/doc.rake +0 -905
  223. data/tasks/example_viewer.html.erb +0 -172
  224. data/tasks/extension.rake +0 -14
  225. data/tasks/license/headers_md.rb +0 -223
  226. data/tasks/license/headers_rb.rb +0 -210
  227. data/tasks/license/license_utils.rb +0 -130
  228. data/tasks/license/snippets_md.rb +0 -315
  229. data/tasks/license/snippets_rdoc.rb +0 -150
  230. data/tasks/license.rake +0 -91
  231. data/tasks/lint.rake +0 -170
  232. data/tasks/rbs_predicates/predicate_catalog.rb +0 -52
  233. data/tasks/rbs_predicates/predicate_tests.rb +0 -124
  234. data/tasks/rbs_predicates/rbs_signature.rb +0 -63
  235. data/tasks/rbs_predicates.rake +0 -31
  236. data/tasks/rdoc_config.rb +0 -29
  237. data/tasks/resources/build.yml.erb +0 -60
  238. data/tasks/resources/index.html.erb +0 -141
  239. data/tasks/resources/rubies.yml +0 -7
  240. data/tasks/sourcehut.rake +0 -122
  241. data/tasks/steep.rake +0 -11
  242. data/tasks/terminal_preview/app_screenshot.rb +0 -45
  243. data/tasks/terminal_preview/crash_report.rb +0 -54
  244. data/tasks/terminal_preview/example_app.rb +0 -27
  245. data/tasks/terminal_preview/launcher_script.rb +0 -48
  246. data/tasks/terminal_preview/preview_collection.rb +0 -60
  247. data/tasks/terminal_preview/preview_timing.rb +0 -24
  248. data/tasks/terminal_preview/safety_confirmation.rb +0 -58
  249. data/tasks/terminal_preview/saved_screenshot.rb +0 -56
  250. data/tasks/terminal_preview/system_appearance.rb +0 -13
  251. data/tasks/terminal_preview/terminal_window.rb +0 -138
  252. data/tasks/terminal_preview/window_id.rb +0 -16
  253. data/tasks/terminal_preview.rake +0 -30
  254. data/tasks/test.rake +0 -36
  255. data/tasks/website/index_page.rb +0 -30
  256. data/tasks/website/version.rb +0 -122
  257. data/tasks/website/version_menu.rb +0 -68
  258. data/tasks/website/versioned_documentation.rb +0 -83
  259. data/tasks/website/website.rb +0 -53
  260. data/tasks/website.rake +0 -28
@@ -1,112 +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
- # A custom widget that fills its area with a checkered pattern using Cell objects.
12
- class CheckeredBackground
13
- def initialize(tui)
14
- @tui = tui
15
- end
16
-
17
- def render(area)
18
- cell = @tui.cell(char: "░", fg: :dark_gray)
19
- commands = []
20
- area.height.times do |y|
21
- area.width.times do |x|
22
- # Checkerboard logic
23
- if (x + y).even?
24
- # Use a dim cell for the background pattern
25
- commands << @tui.draw_cell(area.x + x, area.y + y, cell)
26
- end
27
- end
28
- end
29
- commands
30
- end
31
- end
32
-
33
- class WidgetCell
34
- def run
35
- RatatuiRuby.run do |tui|
36
- @tui = tui
37
- # Define some reusable cells for our table
38
- ok_cell = @tui.cell(char: "OK", fg: :green)
39
- fail_cell = @tui.cell(char: "FAIL", fg: :red, modifiers: ["bold"])
40
- pending_cell = @tui.cell(char: "...", fg: :yellow, modifiers: ["dim"])
41
-
42
- # A mix of Strings and Cells in rows
43
- rows = [
44
- ["Database", ok_cell],
45
- ["Cache", ok_cell],
46
- ["Worker", fail_cell],
47
- ["Analytics", pending_cell],
48
- ["Web Server", @tui.cell(char: "RESTARTING", fg: :blue, modifiers: ["rapid_blink"])],
49
- ]
50
-
51
- table = @tui.table(
52
- header: ["Service", @tui.cell(char: "Status", modifiers: ["underlined"])],
53
- rows:,
54
- widths: [
55
- @tui.constraint_percentage(70),
56
- @tui.constraint_percentage(30),
57
- ],
58
- block: @tui.block(title: "System Status", borders: :all),
59
- column_spacing: 1
60
- )
61
-
62
- # Main loop
63
- loop do
64
- @tui.draw do |frame|
65
- # Create a layout that holds both widgets
66
- # We use a vertical layout:
67
- # Top: Custom CheckeredBackground with specific height
68
- # Bottom: Table using remaining space
69
- top_area, bottom_area = @tui.layout_split(
70
- frame.area,
71
- direction: :vertical,
72
- constraints: [
73
- @tui.constraint_length(10), # Top section
74
- @tui.constraint_min(0), # Bottom section
75
- ]
76
- )
77
-
78
- # Top Child: An Overlay of Paragraph on top of CheckeredBackground
79
- overlay = @tui.overlay(
80
- layers: [
81
- CheckeredBackground.new(@tui),
82
- @tui.center(
83
- width_percent: 50,
84
- height_percent: 50,
85
- child: @tui.paragraph(
86
- text: "Custom Widget\n(CheckeredBackground)",
87
- alignment: :center,
88
- block: @tui.block(borders: :all, title: "Overlay")
89
- )
90
- ),
91
- ]
92
- )
93
- frame.render_widget(overlay, top_area)
94
-
95
- # Bottom Child: The Table
96
- frame.render_widget(table, bottom_area)
97
- end
98
-
99
- case @tui.poll_event
100
- in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
101
- break
102
- else
103
- nil
104
- end
105
- end
106
- end
107
- end
108
- end
109
-
110
- if __FILE__ == $0
111
- WidgetCell.new.run
112
- end
@@ -1,33 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
- # Center Example
6
-
7
- [![widget_center](../../doc/images/widget_center.png)](app.rb)
8
-
9
- <!--
10
- SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
11
- SPDX-License-Identifier: CC-BY-SA-4.0
12
- -->
13
-
14
- This example demonstrates the `Center` widget, which positions a child widget in the center of the available area.
15
-
16
- ## Key Concepts
17
-
18
- - **Centering**: The widget automatically calculates the necessary padding to center its child.
19
- - **Sizing**: You can control the size of the centered area using `width_percent` and `height_percent`.
20
- - **Composition**: The `Center` widget wraps another widget (the child), making it easy to compose layouts.
21
-
22
- ## Controls
23
-
24
- | Key | Action |
25
- | --- | --- |
26
- | `←` / `→` | Decrease / Increase width percentage |
27
- | `↑` / `↓` | Increase / Decrease height percentage |
28
- | `q` | Quit |
29
-
30
- ## Screenshot
31
- ## Source Code
32
-
33
- - [app.rb](app.rb)
@@ -1,118 +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
- # Center Widget
12
- # Demonstrates how to center content horizontally and vertically
13
- # with adjustable width/height percentages.
14
- class WidgetCenter
15
- def initialize
16
- @width_percent = 50
17
- @height_percent = 50
18
- end
19
-
20
- def run
21
- RatatuiRuby.run do |tui|
22
- @tui = tui
23
- loop do
24
- render
25
- break if handle_input == :quit
26
- end
27
- end
28
- end
29
-
30
- private def render
31
- @tui.draw do |frame|
32
- layout = @tui.layout_split(
33
- frame.area,
34
- direction: :vertical,
35
- constraints: [
36
- @tui.constraint_fill(1),
37
- @tui.constraint_length(3),
38
- ]
39
- )
40
-
41
- # 1. Main Area
42
- # Background block frames the centered content
43
- bg_block = @tui.block(
44
- title: "Center Widget",
45
- borders: [:all],
46
- style: @tui.style(fg: :gray)
47
- )
48
- frame.render_widget(bg_block, layout[0])
49
-
50
- # 2. Centered Content
51
- # The content itself is just a block with some text
52
- content = @tui.paragraph(
53
- text: [
54
- @tui.text_line(
55
- spans: [
56
- @tui.text_span(content: "Centered Area", style: @tui.style(modifiers: [:bold])),
57
- ],
58
- alignment: :center
59
- ),
60
- @tui.text_line(spans: []),
61
- @tui.text_line(spans: [@tui.text_span(content: "Width: #{@width_percent}%", style: @tui.style(fg: :cyan))], alignment: :center),
62
- @tui.text_line(spans: [@tui.text_span(content: "Height: #{@height_percent}%", style: @tui.style(fg: :magenta))], alignment: :center),
63
- ],
64
- block: @tui.block(
65
- title: "Child Widget",
66
- borders: [:all],
67
- style: @tui.style(fg: :white)
68
- ),
69
- alignment: :center
70
- )
71
-
72
- # Create the Center widget
73
- center_widget = @tui.center(
74
- child: content,
75
- width_percent: @width_percent,
76
- height_percent: @height_percent
77
- )
78
-
79
- # Render center widget into the main layout area
80
- frame.render_widget(center_widget, layout[0])
81
-
82
- # 3. Controls
83
- control_text = @tui.paragraph(
84
- text: [
85
- @tui.text_line(spans: [
86
- @tui.text_span(content: "←/→", style: @tui.style(modifiers: [:bold, :underlined])),
87
- @tui.text_span(content: ": Width "),
88
- @tui.text_span(content: "↑/↓", style: @tui.style(modifiers: [:bold, :underlined])),
89
- @tui.text_span(content: ": Height "),
90
- @tui.text_span(content: "q", style: @tui.style(modifiers: [:bold, :underlined])),
91
- @tui.text_span(content: ": Quit"),
92
- ]),
93
- ],
94
- block: @tui.block(borders: [:top], style: @tui.style(bg: :black))
95
- )
96
- frame.render_widget(control_text, layout[1])
97
- end
98
- end
99
-
100
- def handle_input
101
- case @tui.poll_event
102
- in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
103
- :quit
104
- in { type: :key, code: "left" }
105
- @width_percent = [@width_percent - 5, 5].max
106
- in { type: :key, code: "right" }
107
- @width_percent = [@width_percent + 5, 100].min
108
- in { type: :key, code: "up" }
109
- @height_percent = [@height_percent + 5, 100].min
110
- in { type: :key, code: "down" }
111
- @height_percent = [@height_percent - 5, 5].max
112
- else
113
- # Ignore other events
114
- end
115
- end
116
- end
117
-
118
- WidgetCenter.new.run if __FILE__ == $0
@@ -1,50 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
-
6
- # Chart (Dataset, Axis) Example
7
-
8
- [![widget_chart](../../doc/images/widget_chart.png)](app.rb)
9
-
10
- Demonstrates Cartesian plotting with interactive styling and configuration.
11
-
12
- Trends and patterns are invisible in raw logs. Charts visualize X/Y datasets to reveal the story behind the data.
13
-
14
- ## Features Demonstrated
15
-
16
- - **Dataset Types**: Line charts and Scatter plots.
17
- - **Markers**: Braille patterns, dots, blocks, and bars.
18
- - **Axis Configuration**: Controlling labels, bounds, and alignment (Left/Center/Right).
19
- - **Legend**: Positioning the legend in any of the four corners or hiding it based on constraints.
20
-
21
- ## Hotkeys
22
-
23
- - **m**: Cycle Marker Type (`marker`)
24
- - **s**: Cycle Dataset Style (`style`)
25
- - **x**: Cycle X-Axis Alignment (`labels_alignment`)
26
- - **y**: Cycle Y-Axis Alignment (`labels_alignment`)
27
- - **l**: Cycle Legend Position (`legend_position`)
28
- - **q**: Quit
29
-
30
- ## Usage
31
-
32
- <!-- SPDX-SnippetBegin -->
33
- <!--
34
- SPDX-FileCopyrightText: 2026 Kerrick Long
35
- SPDX-License-Identifier: MIT-0
36
- -->
37
- ```bash
38
- ruby examples/widget_chart/app.rb
39
- ```
40
- <!-- SPDX-SnippetEnd -->
41
-
42
- ## Learning Outcomes
43
-
44
- Use this example if you need to...
45
-
46
- - Plot real-time data monitoring (CPU history, request latency).
47
- - Visualize mathematical functions.
48
- - Compare multiple datasets on the same axis.
49
-
50
- [Read the source code →](app.rb)
@@ -1,220 +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 Cartesian plotting attributes with interactive cycling.
12
- #
13
- # Trends and patterns are invisible in raw logs. You need to see the shape of the data to understand the story it tells.
14
- #
15
- # This demo showcases the <tt>Chart</tt> widget. It provides an interactive playground where you can toggle marker types, axis alignments, and legend positions in real-time.
16
- #
17
- # Use it to understand how to visualize complex X/Y datasets and trends efficiently.
18
- #
19
- # === Example
20
- #
21
- # Run the demo from the terminal:
22
- #
23
- # ruby examples/widget_chart/app.rb
24
- #
25
- # rdoc-image:/doc/images/widget_chart.png
26
- class WidgetChart
27
- MARKERS = [
28
- { name: "Dot (·)", marker: :dot },
29
- { name: "Braille", marker: :braille },
30
- { name: "Block (█)", marker: :block },
31
- { name: "Bar", marker: :bar },
32
- ].freeze
33
-
34
- X_ALIGNMENTS = [
35
- { name: "Left", alignment: :left },
36
- { name: "Center", alignment: :center },
37
- { name: "Right", alignment: :right },
38
- ].freeze
39
-
40
- Y_ALIGNMENTS = [
41
- { name: "Left", alignment: :left },
42
- { name: "Center", alignment: :center },
43
- { name: "Right", alignment: :right },
44
- ].freeze
45
-
46
- LEGEND_POSITIONS = [
47
- { name: "Top Right", position: :top_right },
48
- { name: "Top Left", position: :top_left },
49
- { name: "Bottom Right", position: :bottom_right },
50
- { name: "Bottom Left", position: :bottom_left },
51
- ].freeze
52
-
53
- def run
54
- RatatuiRuby.run do |tui|
55
- @tui = tui
56
- init_styles
57
-
58
- # Support seeded random for deterministic testing
59
- # Set RATA_SEED=42 for reproducible scatter plot data
60
- seed = ENV.fetch("RATA_SEED", nil)
61
- @rng = seed ? Random.new(seed.to_i) : Random.new
62
-
63
- @marker_index = 0
64
- @dataset_style_index = 0
65
- @x_alignment_index = 1
66
- @y_alignment_index = 2
67
- @legend_position_index = 0
68
-
69
- loop do
70
- render
71
- break if handle_input == :quit
72
- sleep 0.05
73
- end
74
- end
75
- end
76
-
77
- private def init_styles
78
- @hotkey_style = @tui.style(modifiers: [:bold, :underlined])
79
- @dataset_styles = [
80
- { name: "Yellow", style: @tui.style(fg: :yellow) },
81
- { name: "Green", style: @tui.style(fg: :green) },
82
- { name: "Cyan", style: @tui.style(fg: :cyan) },
83
- { name: "Red", style: @tui.style(fg: :red) },
84
- { name: "Magenta", style: @tui.style(fg: :magenta) },
85
- { name: "Bold Blue", style: @tui.style(fg: :blue, modifiers: [:bold]) },
86
- { name: "Dim White", style: @tui.style(fg: :white, modifiers: [:dim]) },
87
- { name: "Italic Green", style: @tui.style(fg: :green, modifiers: [:italic]) },
88
- { name: "Alert (Red/White/Bar)", style: @tui.style(fg: :white, bg: :red, modifiers: [:bold]) },
89
- ]
90
- end
91
-
92
- private def render
93
- # Static sample data: sine wave with wider range for better visibility
94
- line_data = (0..50).map do |i|
95
- x = i / 5.0
96
- [x, Math.sin(x)]
97
- end
98
-
99
- # Scatter: Random points (deterministic when RATA_SEED is set)
100
- scatter_data = (0..20).map do |_|
101
- [@rng.rand(0.0..10.0), @rng.rand(-1.0..1.0)]
102
- end
103
-
104
- style = @dataset_styles[@dataset_style_index][:style]
105
- # Ensure the second dataset has a different style
106
- scatter_style = @dataset_styles[(@dataset_style_index + 2) % @dataset_styles.length][:style]
107
-
108
- datasets = [
109
- @tui.dataset(
110
- name: "Line",
111
- data: line_data,
112
- style:,
113
- marker: (style.modifiers.include?(:bold) && style.bg) ? :bar : MARKERS[@marker_index][:marker],
114
- graph_type: :line
115
- ),
116
- @tui.dataset(
117
- name: "Scatter",
118
- data: scatter_data,
119
- style: scatter_style,
120
- marker: (scatter_style.modifiers.include?(:bold) && scatter_style.bg) ? :bar : MARKERS[@marker_index][:marker],
121
- graph_type: :scatter
122
- ),
123
- ]
124
-
125
- chart = @tui.chart(
126
- datasets:,
127
- x_axis: @tui.axis(
128
- title: "Time",
129
- bounds: [0.0, 10.0],
130
- labels: %w[0 5 10],
131
- style: @tui.style(fg: :yellow),
132
- labels_alignment: X_ALIGNMENTS[@x_alignment_index][:alignment]
133
- ),
134
- y_axis: @tui.axis(
135
- title: "Amplitude",
136
- bounds: [-1.0, 1.0],
137
- labels: %w[-1 0 1],
138
- style: @tui.style(fg: :cyan),
139
- labels_alignment: Y_ALIGNMENTS[@y_alignment_index][:alignment]
140
- ),
141
- block: @tui.block(
142
- title: "Chart Widget",
143
- borders: [:all]
144
- ),
145
- legend_position: LEGEND_POSITIONS[@legend_position_index][:position],
146
- hidden_legend_constraints: [
147
- @tui.constraint_min(20),
148
- @tui.constraint_min(10),
149
- ]
150
- )
151
-
152
- controls = @tui.block(
153
- title: "Controls",
154
- borders: [:all],
155
- children: [
156
- @tui.paragraph(
157
- text: [
158
- # Line 1: Markers & Colors
159
- @tui.text_line(spans: [
160
- @tui.text_span(content: "m", style: @hotkey_style),
161
- @tui.text_span(content: ": Marker (#{MARKERS[@marker_index][:name]}) "),
162
- @tui.text_span(content: "s", style: @hotkey_style),
163
- @tui.text_span(content: ": Style (#{@dataset_styles[@dataset_style_index][:name]})"),
164
- ]),
165
- # Line 2: Axis alignments
166
- @tui.text_line(spans: [
167
- @tui.text_span(content: "x", style: @hotkey_style),
168
- @tui.text_span(content: ": X Align (#{X_ALIGNMENTS[@x_alignment_index][:name]}) "),
169
- @tui.text_span(content: "y", style: @hotkey_style),
170
- @tui.text_span(content: ": Y Align (#{Y_ALIGNMENTS[@y_alignment_index][:name]}) "),
171
- @tui.text_span(content: "l", style: @hotkey_style),
172
- @tui.text_span(content: ": Legend (#{LEGEND_POSITIONS[@legend_position_index][:name]})"),
173
- ]),
174
- # Line 3: Quit
175
- @tui.text_line(spans: [
176
- @tui.text_span(content: "q", style: @hotkey_style),
177
- @tui.text_span(content: ": Quit"),
178
- ]),
179
- ]
180
- ),
181
- ]
182
- )
183
-
184
- @tui.draw do |frame|
185
- chart_area, controls_area = @tui.layout_split(
186
- frame.area,
187
- direction: :vertical,
188
- constraints: [
189
- @tui.constraint_fill(1),
190
- @tui.constraint_length(5),
191
- ]
192
- )
193
- frame.render_widget(chart, chart_area)
194
- frame.render_widget(controls, controls_area)
195
- end
196
- end
197
-
198
- private def handle_input
199
- event = @tui.poll_event
200
-
201
- case event
202
- in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
203
- :quit
204
- in type: :key, code: "m"
205
- @marker_index = (@marker_index + 1) % MARKERS.length
206
- in type: :key, code: "s"
207
- @dataset_style_index = (@dataset_style_index + 1) % @dataset_styles.length
208
- in type: :key, code: "x"
209
- @x_alignment_index = (@x_alignment_index + 1) % X_ALIGNMENTS.length
210
- in type: :key, code: "y"
211
- @y_alignment_index = (@y_alignment_index + 1) % Y_ALIGNMENTS.length
212
- in type: :key, code: "l"
213
- @legend_position_index = (@legend_position_index + 1) % LEGEND_POSITIONS.length
214
- else
215
- nil
216
- end
217
- end
218
- end
219
-
220
- WidgetChart.new.run if __FILE__ == $PROGRAM_NAME
@@ -1,50 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
-
6
- # Gauge Widget Example
7
-
8
- [![widget_gauge](../../doc/images/widget_gauge.png)](app.rb)
9
-
10
- Demonstrates progress bars with interactive configuration.
11
-
12
- Long-running tasks create anxiety. Users need to know the system is working. Gauges provide visual feedback on completion status.
13
-
14
- ## Features Demonstrated
15
-
16
- - **Progress styles**: standard block characters or Unicode bars.
17
- - **Labels**: Customizing the text overlay (Percentage, Ratio, etc.).
18
- - **Styling**: Independent control of the filled gauge color and the background track.
19
- - **Thresholds**: Implementing multi-colored gauges based on values.
20
-
21
- ## Hotkeys
22
-
23
- - **Arrows (←/→)**: Adjust Ratio (`ratio`)
24
- - **g**: Cycle Gauge Color (`gauge_style`)
25
- - **b**: Cycle Background Style (`style`)
26
- - **u**: Toggle Unicode Mode (`use_unicode`)
27
- - **l**: Cycle Label Mode (`label`)
28
- - **q**: Quit
29
-
30
- ## Usage
31
-
32
- <!-- SPDX-SnippetBegin -->
33
- <!--
34
- SPDX-FileCopyrightText: 2026 Kerrick Long
35
- SPDX-License-Identifier: MIT-0
36
- -->
37
- ```bash
38
- ruby examples/widget_gauge/app.rb
39
- ```
40
- <!-- SPDX-SnippetEnd -->
41
-
42
- ## Learning Outcomes
43
-
44
- Use this example if you need to...
45
-
46
- - Show download or upload progress.
47
- - Visualize resource quotas (disk space, memory usage).
48
- - Create "health bars" or status indicators.
49
-
50
- [Read the source code →](app.rb)