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,48 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
-
6
- # Map (World Map, Canvas) Example
7
-
8
- [![widget_map](../../doc/images/widget_map.png)](app.rb)
9
-
10
- Demonstrates drawing custom graphics and maps using the standard Braille and Block patterns.
11
-
12
- Standard widgets are great for text, but sometimes you need to draw. The `Canvas` widget gives you a high-resolution coordinate system (x, y) to render shapes, lines, and data visualizations that go beyond the grid.
13
-
14
- ## Features Demonstrated
15
-
16
- - **High-Resolution Drawing**: Using Braille patterns (`⣿`) to effectively double the vertical and horizontal resolution of the terminal.
17
- - **Layers**: Drawing multiple shapes (Map, Circles, Lines) in a specific order.
18
- - **Animation**: Updating coordinates in a loop to create smooth motion.
19
- - **World Map**: Using the built-in `Map` shape for geographic data.
20
-
21
- ## Hotkeys
22
-
23
- - **b**: Cycle Background Color (`background_color`)
24
- - **m**: Cycle Marker Type (`marker`)
25
- - **l**: Toggle Labels (modifies `shapes`)
26
- - **q**: Quit
27
-
28
- ## Usage
29
-
30
- <!-- SPDX-SnippetBegin -->
31
- <!--
32
- SPDX-FileCopyrightText: 2026 Kerrick Long
33
- SPDX-License-Identifier: MIT-0
34
- -->
35
- ```bash
36
- ruby examples/widget_map/app.rb
37
- ```
38
- <!-- SPDX-SnippetEnd -->
39
-
40
- ## Learning Outcomes
41
-
42
- Use this example if you need to...
43
-
44
- - Render geographic data (World, USA, Europe).
45
- - Overlay custom labels and markers on a map.
46
- - Animate visual elements on top of a static background.
47
-
48
- [Read the source code →](app.rb)
@@ -1,95 +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
- # An example of the Canvas widget showing a world map and animated shapes.
12
- class WidgetMap
13
- include RatatuiRuby::Widgets
14
-
15
- COLORS = [:black, :blue, :white, nil].freeze
16
- MARKERS = [:braille, :half_block, :dot, :block, :bar, :quadrant, :sextant, :octant].freeze
17
-
18
- # Returns a Canvas view for the map demo with the given circle radius.
19
- #
20
- # +tui+:: The RatatuiRuby::TUI instance.
21
- # +radius+:: The radius of the animated circle.
22
- # +marker+:: The marker type.
23
- # +background_color+:: The background color of the canvas.
24
- # +show_labels+:: Whether to show city labels.
25
- def view(tui, radius, marker = :braille, background_color = nil, show_labels: true)
26
- shapes = [
27
- tui.shape_map(color: :green, resolution: :high),
28
- tui.shape_circle(x: 0.0, y: 0.0, radius:, color: :red),
29
- tui.shape_line(x1: 0.0, y1: 0.0, x2: 50.0, y2: 25.0, color: :yellow),
30
- ]
31
-
32
- if show_labels
33
- shapes += [
34
- tui.shape_label(x: -0.1, y: 51.5, text: "London", style: tui.style(fg: :cyan)),
35
- tui.shape_label(x: 139.7, y: 35.7, text: "Tokyo", style: tui.style(fg: :magenta)),
36
- tui.shape_label(x: -74.0, y: 40.7, text: "New York", style: tui.style(fg: :yellow)),
37
- tui.shape_label(x: -122.4, y: 37.8, text: "San Francisco", style: tui.style(fg: :blue)),
38
- tui.shape_label(x: 151.2, y: -33.9, text: "Sydney", style: tui.style(fg: :green)),
39
- ]
40
- end
41
-
42
- tui.canvas(
43
- shapes:,
44
- x_bounds: [-180.0, 180.0],
45
- y_bounds: [-90.0, 90.0],
46
- marker:,
47
- block: tui.block(title: "World Map ['b' bg, 'm' marker: #{marker}, 'l' labels: #{show_labels ? 'on' : 'off'}]", borders: :all),
48
- background_color:
49
- )
50
- end
51
-
52
- # Runs the map demo loop.
53
- def run
54
- RatatuiRuby.run do |tui|
55
- radius = 0.0
56
- direction = 1
57
- bg_index = 0
58
- marker_index = 0
59
- show_labels = true
60
-
61
- loop do
62
- # Animate the circle radius
63
- radius += 0.5 * direction
64
- if radius > 10.0 || radius < 0.0
65
- direction *= -1
66
- end
67
-
68
- # Define the view
69
- canvas = view(tui, radius, MARKERS[marker_index], COLORS[bg_index], show_labels:)
70
-
71
- tui.draw do |frame|
72
- frame.render_widget(canvas, frame.area)
73
- end
74
-
75
- event = tui.poll_event
76
- case event
77
- in { type: :key, code: "q" } | { type: :key, code: :ctrl_c }
78
- break
79
- in type: :key, code: "b"
80
- bg_index = (bg_index + 1) % COLORS.size
81
- in type: :key, code: "m"
82
- marker_index = (marker_index + 1) % MARKERS.size
83
- in type: :key, code: "l"
84
- show_labels = !show_labels
85
- else
86
- # Ignore other events
87
- end
88
-
89
- sleep 0.05
90
- end
91
- end
92
- end
93
- end
94
-
95
- WidgetMap.new.run if __FILE__ == $PROGRAM_NAME
@@ -1,45 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
- # Overlay Example
6
-
7
- [![](../../doc/images/widget_overlay.png)](app.rb)
8
-
9
- This example demonstrates the `Overlay` composition pattern for layering widgets with depth. Modals, notifications, and floating panels all require stacking widgets on top of each other.
10
-
11
- ## Key Concepts
12
-
13
- - **Layer Composition:** Rendering widgets in order creates visual depth — later renders appear "on top."
14
- - **Clear Widget:** Using `tui.clear` before rendering a modal erases the background, preventing content bleed-through.
15
- - **Dynamic Layer Control:** Toggle the number of visible overlay layers at runtime.
16
- - **Layer Ordering:** Swap which overlay appears in front to demonstrate z-ordering.
17
-
18
- ## Hotkeys
19
-
20
- - `0`/`1`/`2`: Set number of visible overlay layers
21
- - `space`: Swap overlay order (which modal is on top)
22
- - `c`: Toggle Clear widget (on/off)
23
- - `q`: Quit
24
-
25
- ## Usage
26
-
27
- <!-- SPDX-SnippetBegin -->
28
- <!--
29
- SPDX-FileCopyrightText: 2026 Kerrick Long
30
- SPDX-License-Identifier: MIT-0
31
- -->
32
- ```bash
33
- ruby examples/widget_overlay/app.rb
34
- ```
35
- <!-- SPDX-SnippetEnd -->
36
-
37
- ## Learning Outcomes
38
-
39
- Use this example if you need to...
40
-
41
- - Build modal dialogs or confirmation popups.
42
- - Layer notifications over existing content.
43
- - Understand the Clear widget's role in opaque overlays.
44
-
45
- [Read the source code →](app.rb)
@@ -1,250 +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
- HEADLINES = [
12
- "Scientists Discover New Species of Deep-Sea Octopus Near Hawaii",
13
- "Global Climate Summit Reaches Historic Agreement on Emissions",
14
- "Tech Giant Announces Breakthrough in Quantum Computing Research",
15
- "Local Community Garden Initiative Expands to Ten More Cities",
16
- "Astronomers Detect Unusual Radio Signals from Distant Galaxy",
17
- "New Study Links Mediterranean Diet to Improved Heart Health",
18
- "Electric Vehicle Sales Surge as Battery Technology Improves",
19
- "Ancient Manuscripts Reveal Previously Unknown Trading Routes",
20
- "Renewable Energy Now Powers 40% of National Grid",
21
- "Robotics Team Develops AI System for Disaster Response",
22
- "Archaeological Dig Uncovers Evidence of Early Human Settlement",
23
- "Major Airline Commits to Carbon-Neutral Flights by 2035",
24
- "Breakthrough Treatment Shows Promise for Rare Genetic Disease",
25
- "City Council Approves Expanded Public Transportation Network",
26
- "Marine Biologists Track Migration Patterns of Endangered Whales",
27
- "New App Helps Farmers Optimize Water Usage During Drought",
28
- "International Space Station Extends Mission Timeline to 2030",
29
- "Local Schools Implement Innovative STEM Education Program",
30
- "Wildlife Conservation Efforts Lead to Species Population Recovery",
31
- "Research Team Creates Biodegradable Alternative to Plastic Packaging",
32
- "Historic Theater Restoration Project Nears Completion",
33
- "Cybersecurity Experts Warn of Emerging Online Threats",
34
- "Community Food Bank Serves Record Number of Families This Year",
35
- "Innovative Urban Planning Reduces Traffic Congestion by 30%",
36
- ].freeze
37
-
38
- # Overlay Example
39
- # Demonstrates the Overlay widget for layering widgets with depth.
40
- class WidgetOverlay
41
- def initialize
42
- @layer_count = 2 # Start with 2 layers visible
43
- @swapped = false
44
- @clear = true
45
- end
46
-
47
- def run
48
- RatatuiRuby.run do |tui|
49
- @tui = tui
50
- loop do
51
- tui.draw do |frame|
52
- render(frame)
53
- end
54
- break if handle_input == :quit
55
- sleep 0.05
56
- end
57
- end
58
- end
59
-
60
- private def render(frame)
61
- area = frame.area
62
-
63
- # Split into main area and control panel
64
- layout = @tui.layout_split(
65
- area,
66
- direction: :vertical,
67
- constraints: [
68
- @tui.constraint_fill(1),
69
- @tui.constraint_length(5),
70
- ]
71
- )
72
-
73
- main_area = layout[0]
74
- control_area = layout[1]
75
-
76
- # Render background layer - RSS reader
77
- frame.render_widget(background_layer, main_area)
78
-
79
- # Render upper layers based on layer_count and swap state
80
- if @swapped
81
- render_beta_layer(frame, main_area) if @layer_count >= 2
82
- render_notification_layer(frame, main_area) if @layer_count >= 1
83
- else
84
- render_notification_layer(frame, main_area) if @layer_count >= 1
85
- render_beta_layer(frame, main_area) if @layer_count >= 2
86
- end
87
-
88
- # Render control panel
89
- frame.render_widget(control_panel, control_area)
90
- end
91
-
92
- def background_layer
93
- @background_layer ||= @tui.list(
94
- items: HEADLINES,
95
- block: @tui.block(
96
- title: "RSS Reader",
97
- borders: [:all]
98
- )
99
- )
100
- end
101
-
102
- def render_notification_layer(frame, area)
103
- # Position modal: 20% from top, 60% height, 15% from left, 70% width
104
-
105
- vertical_sections = @tui.layout_split(
106
- area,
107
- direction: :vertical,
108
- constraints: [
109
- @tui.constraint_fill(2),
110
- @tui.constraint_fill(5),
111
- @tui.constraint_fill(3),
112
- ]
113
- )
114
-
115
- horizontal_sections = @tui.layout_split(
116
- vertical_sections[1],
117
- direction: :horizontal,
118
- constraints: [
119
- @tui.constraint_fill(1),
120
- @tui.constraint_fill(5),
121
- @tui.constraint_fill(1),
122
- ]
123
- )
124
-
125
- modal_rect = horizontal_sections[1]
126
-
127
- frame.render_widget(@tui.clear, modal_rect) if @clear
128
-
129
- # Render the modal content
130
- frame.render_widget(
131
- @tui.paragraph(
132
- text: "Your feeds have been updated",
133
- wrap: true,
134
- alignment: :center,
135
- block: @tui.block(
136
- title: "Notification",
137
- borders: [:all],
138
- border_style: @tui.style(fg: :black),
139
- style: @tui.style(bg: :red, fg: :black)
140
- )
141
- ),
142
- modal_rect
143
- )
144
- end
145
-
146
- def render_beta_layer(frame, area)
147
- # Position modal: 30% from top, 40% height, 25% from left, 50% width
148
-
149
- vertical_sections = @tui.layout_split(
150
- area,
151
- direction: :vertical,
152
- constraints: [
153
- @tui.constraint_fill(3),
154
- @tui.constraint_fill(4),
155
- @tui.constraint_fill(2),
156
- ]
157
- )
158
-
159
- horizontal_sections = @tui.layout_split(
160
- vertical_sections[1],
161
- direction: :horizontal,
162
- constraints: [
163
- @tui.constraint_fill(2),
164
- @tui.constraint_fill(3),
165
- @tui.constraint_fill(2),
166
- ]
167
- )
168
-
169
- modal_rect = horizontal_sections[1]
170
-
171
- frame.render_widget(@tui.clear, modal_rect) if @clear
172
-
173
- # Render the modal content
174
- frame.render_widget(
175
- beta_paragraph,
176
- modal_rect
177
- )
178
- end
179
-
180
- def beta_paragraph
181
- @beta_paragraph ||= @tui.paragraph(
182
- text: "Thank you for being a beta tester. To give feedback, shout very loudly and we will hear you. Be careful not to scare the llamas.",
183
- wrap: true,
184
- alignment: :left,
185
- block: @tui.block(
186
- title: "Beta Program",
187
- borders: [:all],
188
- border_style: @tui.style(fg: :black),
189
- style: @tui.style(bg: :blue, fg: :black)
190
- )
191
- )
192
- end
193
-
194
- def control_panel
195
- bold_underline = @tui.style(modifiers: [:bold, :underlined])
196
-
197
- first_controls = [
198
- @tui.text_span(content: "0", style: bold_underline),
199
- @tui.text_span(content: "/"),
200
- @tui.text_span(content: "1", style: bold_underline),
201
- @tui.text_span(content: "/"),
202
- @tui.text_span(content: "2", style: bold_underline),
203
- @tui.text_span(content: ": Change number of overlays | "),
204
- @tui.text_span(content: "space", style: bold_underline),
205
- @tui.text_span(content: ": Swap overlay order"),
206
- ]
207
- second_controls = [
208
- @tui.text_span(content: "c", style: bold_underline),
209
- @tui.text_span(content: ": Toggle clear (currently #{@clear ? 'on' : 'off'})"),
210
- ]
211
- third_controls = [
212
- @tui.text_span(content: "q", style: bold_underline),
213
- @tui.text_span(content: ": Quit"),
214
- ]
215
-
216
- first = @tui.text_line(spans: first_controls)
217
- second = @tui.text_line(spans: second_controls)
218
- third = @tui.text_line(spans: third_controls)
219
-
220
- @tui.paragraph(
221
- text: [first, second, third],
222
- alignment: :center,
223
- block: @tui.block(
224
- title: "Controls",
225
- borders: [:all]
226
- )
227
- )
228
- end
229
-
230
- def handle_input
231
- case @tui.poll_event
232
- in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
233
- :quit
234
- in { type: :key, code: "0" }
235
- @layer_count = 0
236
- in { type: :key, code: "1" }
237
- @layer_count = 1
238
- in { type: :key, code: "2" }
239
- @layer_count = 2
240
- in { type: :key, code: " " }
241
- @swapped = !@swapped
242
- in { type: :key, code: "c" }
243
- @clear = !@clear
244
- else
245
- nil
246
- end
247
- end
248
- end
249
-
250
- WidgetOverlay.new.run if __FILE__ == $PROGRAM_NAME
@@ -1,45 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
-
6
- # Clear (Popup, Modal) Example
7
-
8
- [![widget_popup](../../doc/images/widget_popup.png)](app.rb)
9
-
10
- Demonstrates how to render opaque overlays on top of content.
11
-
12
- Terminal renders are additive. If you draw a new widget over an old one, the background colors might mix if not handled correctly. The `Clear` widget resets the area to default (usually transparent/black) to ensure a clean canvas for popups.
13
-
14
- ## Features Demonstrated
15
-
16
- - **The `Clear` Widget**: Printing spaces over an area to "erase" what was underneath.
17
- - **Centering**: Using `Layout` constraints to perfectly center a block on screen.
18
- - **Style Bleed**: showing what happens when you *don't* use `Clear` (background colors leak through).
19
-
20
- ## Hotkeys
21
-
22
- - **Space**: Toggle Clear Widget (Observe the red background effect when disabled)
23
- - **q**: Quit
24
-
25
- ## Usage
26
-
27
- <!-- SPDX-SnippetBegin -->
28
- <!--
29
- SPDX-FileCopyrightText: 2026 Kerrick Long
30
- SPDX-License-Identifier: MIT-0
31
- -->
32
- ```bash
33
- ruby examples/widget_popup/app.rb
34
- ```
35
- <!-- SPDX-SnippetEnd -->
36
-
37
- ## Learning Outcomes
38
-
39
- Use this example if you need to...
40
-
41
- - Create a modal dialog (Confirm, Alert, Form).
42
- - Implement a dropdown menu that overlays other content.
43
- - Fix visual artifacts where old text shows through new widgets.
44
-
45
- [Read the source code →](app.rb)
@@ -1,106 +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
- # Popup Example
12
- # Demonstrates the Clear widget for creating opaque popups.
13
-
14
- class WidgetPopup
15
- def initialize
16
- @clear_enabled = false
17
- end
18
-
19
- def run
20
- RatatuiRuby.run do |tui|
21
- loop do
22
- tui.draw do |frame|
23
- render(tui, frame)
24
- end
25
- break if handle_input(tui) == :quit
26
- sleep 0.05
27
- end
28
- end
29
- end
30
-
31
- private def render(tui, frame)
32
- area = frame.area
33
-
34
- # 1. Background: Loud Red Background
35
- # This demonstrates "Style Bleed" where the background color persists
36
- # unless explicitly cleared or overwritten.
37
- background = tui.paragraph(
38
- text: "BACKGROUND RED " * 100,
39
- style: tui.style(bg: :red, fg: :white),
40
- wrap: true
41
- )
42
- frame.render_widget(background, area)
43
-
44
- # 2. Popup Area Calculation
45
- # Center the popup vertically and horizontally
46
- vertical_layout = tui.layout_split(
47
- area,
48
- direction: :vertical,
49
- constraints: [
50
- tui.constraint_percentage(25),
51
- tui.constraint_percentage(50), # 50% height
52
- tui.constraint_percentage(25),
53
- ]
54
- )
55
- popup_area_vertical = vertical_layout[1]
56
-
57
- horizontal_layout = tui.layout_split(
58
- popup_area_vertical,
59
- direction: :horizontal,
60
- constraints: [
61
- tui.constraint_percentage(20),
62
- tui.constraint_percentage(60), # 60% width
63
- tui.constraint_percentage(20),
64
- ]
65
- )
66
- popup_area = horizontal_layout[1]
67
-
68
- # 3. Popup Content
69
- # Without Clear, this will "inherit" the red background from underneath.
70
- popup_text = if @clear_enabled
71
- "✓ Clear is ENABLED\n\nResets background to default\n(Usually Black/Transparent)\n\nPress Space to toggle"
72
- else
73
- "✗ Clear is DISABLED\n\nStyle Bleed: Popup is RED!\n(Inherits background style)\n\nPress Space to toggle"
74
- end
75
-
76
- popup_content = tui.paragraph(
77
- text: popup_text,
78
- alignment: :center,
79
- block: tui.block(
80
- title: "Popup (q to quit, space to toggle)",
81
- borders: [:all]
82
- )
83
- )
84
-
85
- # 4. Render Popup
86
- if @clear_enabled
87
- # With Clear: Resets the style in the popup area before rendering content
88
- frame.render_widget(tui.clear, popup_area)
89
- end
90
-
91
- frame.render_widget(popup_content, popup_area)
92
- end
93
-
94
- private def handle_input(tui)
95
- case tui.poll_event
96
- in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
97
- :quit
98
- in type: :key, code: " "
99
- @clear_enabled = !@clear_enabled
100
- else
101
- nil
102
- end
103
- end
104
- end
105
-
106
- WidgetPopup.new.run if __FILE__ == $0
@@ -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
- # Ratatui Logo Example
7
-
8
- [![widget_ratatui_logo](../../doc/images/widget_ratatui_logo.png)](app.rb)
9
-
10
- Demonstrates branding with the official logo widget.
11
-
12
- A polished application often needs an "About" screen or a splash screen. This widget provides the standardized project branding.
13
-
14
- ## Features Demonstrated
15
-
16
- - **RatatuiLogo Widget**: Renders the Ratatui ASCII art logo.
17
- - **Centering**: Techniques for centering fixed-size content in a fluid layout.
18
-
19
- ## Hotkeys
20
-
21
- - **q**: 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_ratatui_logo/app.rb
32
- ```
33
- <!-- SPDX-SnippetEnd -->
34
-
35
- ## Learning Outcomes
36
-
37
- Use this example if you need to...
38
-
39
- - Create a splash screen.
40
- - Add an "About" modal to your application.
41
- - See how to center a widget both vertically and horizontally.
42
-
43
- [Read the source code →](app.rb)