ratatui_ruby 1.0.0 → 1.0.1

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 (236) hide show
  1. checksums.yaml +4 -4
  2. data/ext/ratatui_ruby/Cargo.lock +1 -1
  3. data/ext/ratatui_ruby/Cargo.toml +1 -1
  4. data/lib/ratatui_ruby/version.rb +1 -1
  5. metadata +1 -232
  6. data/.builds/ruby-3.2.yml +0 -54
  7. data/.builds/ruby-3.3.yml +0 -54
  8. data/.builds/ruby-3.4.yml +0 -54
  9. data/.builds/ruby-4.0.0.yml +0 -54
  10. data/.pre-commit-config.yaml +0 -16
  11. data/.rubocop.yml +0 -10
  12. data/AGENTS.md +0 -146
  13. data/CHANGELOG.md +0 -710
  14. data/README.md +0 -187
  15. data/README.rdoc +0 -302
  16. data/Rakefile +0 -11
  17. data/Steepfile +0 -49
  18. data/doc/concepts/application_architecture.md +0 -321
  19. data/doc/concepts/application_testing.md +0 -193
  20. data/doc/concepts/async.md +0 -190
  21. data/doc/concepts/custom_widgets.md +0 -247
  22. data/doc/concepts/debugging.md +0 -401
  23. data/doc/concepts/event_handling.md +0 -162
  24. data/doc/concepts/interactive_design.md +0 -146
  25. data/doc/contributors/auditing/parity.md +0 -239
  26. data/doc/contributors/design/ruby_frontend.md +0 -420
  27. data/doc/contributors/design/rust_backend.md +0 -422
  28. data/doc/contributors/design.md +0 -11
  29. data/doc/contributors/developing_examples.md +0 -400
  30. data/doc/contributors/documentation_style.md +0 -121
  31. data/doc/contributors/index.md +0 -21
  32. data/doc/contributors/todo/align/api_completeness_audit-finished.md +0 -375
  33. data/doc/contributors/todo/align/api_completeness_audit-unfinished.md +0 -206
  34. data/doc/contributors/todo/align/terminal.md +0 -647
  35. data/doc/contributors/todo/future_work.md +0 -169
  36. data/doc/contributors/upstream_requests/tab_rects.md +0 -173
  37. data/doc/contributors/upstream_requests/title_rects.md +0 -132
  38. data/doc/custom.css +0 -22
  39. data/doc/getting_started/quickstart.md +0 -291
  40. data/doc/getting_started/why.md +0 -93
  41. data/doc/images/app_all_events.png +0 -0
  42. data/doc/images/app_cli_rich_moments.gif +0 -0
  43. data/doc/images/app_color_picker.png +0 -0
  44. data/doc/images/app_debugging_showcase.gif +0 -0
  45. data/doc/images/app_debugging_showcase.png +0 -0
  46. data/doc/images/app_login_form.png +0 -0
  47. data/doc/images/app_stateful_interaction.png +0 -0
  48. data/doc/images/verify_quickstart_dsl.png +0 -0
  49. data/doc/images/verify_quickstart_layout.png +0 -0
  50. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  51. data/doc/images/verify_readme_usage.png +0 -0
  52. data/doc/images/widget_barchart.png +0 -0
  53. data/doc/images/widget_block.png +0 -0
  54. data/doc/images/widget_box.png +0 -0
  55. data/doc/images/widget_calendar.png +0 -0
  56. data/doc/images/widget_canvas.png +0 -0
  57. data/doc/images/widget_cell.png +0 -0
  58. data/doc/images/widget_center.png +0 -0
  59. data/doc/images/widget_chart.png +0 -0
  60. data/doc/images/widget_gauge.png +0 -0
  61. data/doc/images/widget_layout_split.png +0 -0
  62. data/doc/images/widget_line_gauge.png +0 -0
  63. data/doc/images/widget_list.png +0 -0
  64. data/doc/images/widget_map.png +0 -0
  65. data/doc/images/widget_overlay.png +0 -0
  66. data/doc/images/widget_popup.png +0 -0
  67. data/doc/images/widget_ratatui_logo.png +0 -0
  68. data/doc/images/widget_ratatui_mascot.png +0 -0
  69. data/doc/images/widget_rect.png +0 -0
  70. data/doc/images/widget_render.png +0 -0
  71. data/doc/images/widget_rich_text.png +0 -0
  72. data/doc/images/widget_scroll_text.png +0 -0
  73. data/doc/images/widget_scrollbar.png +0 -0
  74. data/doc/images/widget_sparkline.png +0 -0
  75. data/doc/images/widget_style_colors.png +0 -0
  76. data/doc/images/widget_table.png +0 -0
  77. data/doc/images/widget_tabs.png +0 -0
  78. data/doc/images/widget_text_width.png +0 -0
  79. data/doc/index.md +0 -39
  80. data/doc/troubleshooting/async.md +0 -4
  81. data/doc/troubleshooting/terminal_limitations.md +0 -131
  82. data/doc/troubleshooting/tui_output.md +0 -197
  83. data/examples/app_all_events/README.md +0 -114
  84. data/examples/app_all_events/app.rb +0 -98
  85. data/examples/app_all_events/model/app_model.rb +0 -159
  86. data/examples/app_all_events/model/event_color_cycle.rb +0 -43
  87. data/examples/app_all_events/model/event_entry.rb +0 -94
  88. data/examples/app_all_events/model/msg.rb +0 -39
  89. data/examples/app_all_events/model/timestamp.rb +0 -56
  90. data/examples/app_all_events/update.rb +0 -75
  91. data/examples/app_all_events/view/app_view.rb +0 -80
  92. data/examples/app_all_events/view/controls_view.rb +0 -54
  93. data/examples/app_all_events/view/counts_view.rb +0 -61
  94. data/examples/app_all_events/view/live_view.rb +0 -72
  95. data/examples/app_all_events/view/log_view.rb +0 -57
  96. data/examples/app_all_events/view.rb +0 -9
  97. data/examples/app_cli_rich_moments/README.md +0 -81
  98. data/examples/app_cli_rich_moments/app.rb +0 -189
  99. data/examples/app_color_picker/README.md +0 -156
  100. data/examples/app_color_picker/app.rb +0 -76
  101. data/examples/app_color_picker/clipboard.rb +0 -86
  102. data/examples/app_color_picker/color.rb +0 -193
  103. data/examples/app_color_picker/controls.rb +0 -92
  104. data/examples/app_color_picker/copy_dialog.rb +0 -168
  105. data/examples/app_color_picker/export_pane.rb +0 -128
  106. data/examples/app_color_picker/harmony.rb +0 -58
  107. data/examples/app_color_picker/input.rb +0 -176
  108. data/examples/app_color_picker/main_container.rb +0 -180
  109. data/examples/app_color_picker/palette.rb +0 -111
  110. data/examples/app_debugging_showcase/README.md +0 -119
  111. data/examples/app_debugging_showcase/app.rb +0 -318
  112. data/examples/app_login_form/README.md +0 -58
  113. data/examples/app_login_form/app.rb +0 -109
  114. data/examples/app_stateful_interaction/README.md +0 -35
  115. data/examples/app_stateful_interaction/app.rb +0 -328
  116. data/examples/timeout_demo.rb +0 -45
  117. data/examples/verify_quickstart_dsl/README.md +0 -55
  118. data/examples/verify_quickstart_dsl/app.rb +0 -49
  119. data/examples/verify_quickstart_layout/README.md +0 -77
  120. data/examples/verify_quickstart_layout/app.rb +0 -73
  121. data/examples/verify_quickstart_lifecycle/README.md +0 -68
  122. data/examples/verify_quickstart_lifecycle/app.rb +0 -62
  123. data/examples/verify_readme_usage/README.md +0 -49
  124. data/examples/verify_readme_usage/app.rb +0 -42
  125. data/examples/verify_website_managed/README.md +0 -48
  126. data/examples/verify_website_managed/app.rb +0 -36
  127. data/examples/verify_website_menu/README.md +0 -60
  128. data/examples/verify_website_menu/app.rb +0 -84
  129. data/examples/verify_website_spinner/README.md +0 -44
  130. data/examples/verify_website_spinner/app.rb +0 -34
  131. data/examples/widget_barchart/README.md +0 -58
  132. data/examples/widget_barchart/app.rb +0 -240
  133. data/examples/widget_block/README.md +0 -44
  134. data/examples/widget_block/app.rb +0 -258
  135. data/examples/widget_box/README.md +0 -54
  136. data/examples/widget_box/app.rb +0 -255
  137. data/examples/widget_calendar/README.md +0 -48
  138. data/examples/widget_calendar/app.rb +0 -115
  139. data/examples/widget_canvas/README.md +0 -31
  140. data/examples/widget_canvas/app.rb +0 -130
  141. data/examples/widget_cell/README.md +0 -45
  142. data/examples/widget_cell/app.rb +0 -112
  143. data/examples/widget_center/README.md +0 -33
  144. data/examples/widget_center/app.rb +0 -118
  145. data/examples/widget_chart/README.md +0 -50
  146. data/examples/widget_chart/app.rb +0 -220
  147. data/examples/widget_gauge/README.md +0 -50
  148. data/examples/widget_gauge/app.rb +0 -229
  149. data/examples/widget_layout_split/README.md +0 -53
  150. data/examples/widget_layout_split/app.rb +0 -260
  151. data/examples/widget_line_gauge/README.md +0 -50
  152. data/examples/widget_line_gauge/app.rb +0 -219
  153. data/examples/widget_list/README.md +0 -58
  154. data/examples/widget_list/app.rb +0 -384
  155. data/examples/widget_map/README.md +0 -48
  156. data/examples/widget_map/app.rb +0 -95
  157. data/examples/widget_overlay/README.md +0 -45
  158. data/examples/widget_overlay/app.rb +0 -250
  159. data/examples/widget_popup/README.md +0 -45
  160. data/examples/widget_popup/app.rb +0 -106
  161. data/examples/widget_ratatui_logo/README.md +0 -43
  162. data/examples/widget_ratatui_logo/app.rb +0 -104
  163. data/examples/widget_ratatui_mascot/README.md +0 -43
  164. data/examples/widget_ratatui_mascot/app.rb +0 -95
  165. data/examples/widget_rect/README.md +0 -53
  166. data/examples/widget_rect/app.rb +0 -222
  167. data/examples/widget_render/README.md +0 -46
  168. data/examples/widget_render/app.rb +0 -186
  169. data/examples/widget_render/app.rbs +0 -41
  170. data/examples/widget_rich_text/README.md +0 -44
  171. data/examples/widget_rich_text/app.rb +0 -193
  172. data/examples/widget_scroll_text/README.md +0 -46
  173. data/examples/widget_scroll_text/app.rb +0 -109
  174. data/examples/widget_scrollbar/README.md +0 -46
  175. data/examples/widget_scrollbar/app.rb +0 -155
  176. data/examples/widget_sparkline/README.md +0 -51
  177. data/examples/widget_sparkline/app.rb +0 -277
  178. data/examples/widget_style_colors/README.md +0 -43
  179. data/examples/widget_style_colors/app.rb +0 -83
  180. data/examples/widget_table/README.md +0 -57
  181. data/examples/widget_table/app.rb +0 -279
  182. data/examples/widget_tabs/README.md +0 -50
  183. data/examples/widget_tabs/app.rb +0 -183
  184. data/examples/widget_text_width/README.md +0 -44
  185. data/examples/widget_text_width/app.rb +0 -117
  186. data/migrate_to_buffer.rb +0 -145
  187. data/mise.toml +0 -8
  188. data/tasks/autodoc/examples.rb +0 -87
  189. data/tasks/autodoc/member.rb +0 -58
  190. data/tasks/autodoc/name.rb +0 -21
  191. data/tasks/autodoc.rake +0 -21
  192. data/tasks/bump/cargo_lockfile.rb +0 -21
  193. data/tasks/bump/changelog.rb +0 -47
  194. data/tasks/bump/header.rb +0 -32
  195. data/tasks/bump/history.rb +0 -32
  196. data/tasks/bump/links.rb +0 -69
  197. data/tasks/bump/manifest.rb +0 -33
  198. data/tasks/bump/ruby_gem.rb +0 -49
  199. data/tasks/bump/sem_ver.rb +0 -40
  200. data/tasks/bump/unreleased_section.rb +0 -56
  201. data/tasks/bump.rake +0 -51
  202. data/tasks/doc.rake +0 -887
  203. data/tasks/example_viewer.html.erb +0 -172
  204. data/tasks/extension.rake +0 -14
  205. data/tasks/license/headers_md.rb +0 -223
  206. data/tasks/license/headers_rb.rb +0 -210
  207. data/tasks/license/license_utils.rb +0 -130
  208. data/tasks/license/snippets_md.rb +0 -315
  209. data/tasks/license/snippets_rdoc.rb +0 -150
  210. data/tasks/license.rake +0 -91
  211. data/tasks/lint.rake +0 -170
  212. data/tasks/rdoc_config.rb +0 -29
  213. data/tasks/resources/build.yml.erb +0 -60
  214. data/tasks/resources/index.html.erb +0 -141
  215. data/tasks/resources/rubies.yml +0 -7
  216. data/tasks/sourcehut.rake +0 -110
  217. data/tasks/steep.rake +0 -11
  218. data/tasks/terminal_preview/app_screenshot.rb +0 -45
  219. data/tasks/terminal_preview/crash_report.rb +0 -54
  220. data/tasks/terminal_preview/example_app.rb +0 -27
  221. data/tasks/terminal_preview/launcher_script.rb +0 -48
  222. data/tasks/terminal_preview/preview_collection.rb +0 -60
  223. data/tasks/terminal_preview/preview_timing.rb +0 -24
  224. data/tasks/terminal_preview/safety_confirmation.rb +0 -58
  225. data/tasks/terminal_preview/saved_screenshot.rb +0 -56
  226. data/tasks/terminal_preview/system_appearance.rb +0 -13
  227. data/tasks/terminal_preview/terminal_window.rb +0 -138
  228. data/tasks/terminal_preview/window_id.rb +0 -16
  229. data/tasks/terminal_preview.rake +0 -30
  230. data/tasks/test.rake +0 -33
  231. data/tasks/website/index_page.rb +0 -30
  232. data/tasks/website/version.rb +0 -127
  233. data/tasks/website/version_menu.rb +0 -68
  234. data/tasks/website/versioned_documentation.rb +0 -83
  235. data/tasks/website/website.rb +0 -53
  236. 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)