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,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)