ratatui_ruby 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.builds/ruby-3.2.yml +52 -0
  3. data/.builds/ruby-3.3.yml +52 -0
  4. data/.builds/ruby-3.4.yml +52 -0
  5. data/.builds/ruby-4.0.0.yml +53 -0
  6. data/.pre-commit-config.yaml +9 -2
  7. data/AGENTS.md +53 -5
  8. data/CHANGELOG.md +51 -1
  9. data/README.md +38 -18
  10. data/REUSE.toml +5 -0
  11. data/Rakefile +3 -100
  12. data/{docs → doc}/contributors/index.md +2 -1
  13. data/doc/custom.css +8 -0
  14. data/doc/images/examples-calendar_demo.rb.png +0 -0
  15. data/doc/images/examples-chart_demo.rb.png +0 -0
  16. data/doc/images/examples-custom_widget.rb.png +0 -0
  17. data/doc/images/examples-list_styles.rb.png +0 -0
  18. data/doc/images/examples-popup_demo.rb.gif +0 -0
  19. data/doc/images/examples-quickstart_lifecycle.rb.png +0 -0
  20. data/doc/images/examples-scroll_text.rb.png +0 -0
  21. data/doc/images/examples-stock_ticker.rb.png +0 -0
  22. data/doc/images/examples-table_select.rb.png +0 -0
  23. data/{docs → doc}/index.md +1 -1
  24. data/{docs → doc}/quickstart.md +81 -11
  25. data/examples/analytics.rb +2 -1
  26. data/examples/calendar_demo.rb +55 -0
  27. data/examples/chart_demo.rb +84 -0
  28. data/examples/custom_widget.rb +43 -0
  29. data/examples/list_styles.rb +66 -0
  30. data/examples/login_form.rb +2 -1
  31. data/examples/popup_demo.rb +105 -0
  32. data/examples/quickstart_dsl.rb +30 -0
  33. data/examples/quickstart_lifecycle.rb +40 -0
  34. data/examples/readme_usage.rb +21 -0
  35. data/examples/scroll_text.rb +74 -0
  36. data/examples/stock_ticker.rb +13 -5
  37. data/examples/system_monitor.rb +2 -1
  38. data/examples/table_select.rb +70 -0
  39. data/examples/test_calendar_demo.rb +66 -0
  40. data/examples/test_list_styles.rb +61 -0
  41. data/examples/test_popup_demo.rb +62 -0
  42. data/examples/test_scroll_text.rb +130 -0
  43. data/examples/test_table_select.rb +37 -0
  44. data/ext/ratatui_ruby/.cargo/config.toml +5 -0
  45. data/ext/ratatui_ruby/Cargo.lock +260 -50
  46. data/ext/ratatui_ruby/Cargo.toml +5 -4
  47. data/ext/ratatui_ruby/extconf.rb +1 -1
  48. data/ext/ratatui_ruby/src/buffer.rs +54 -0
  49. data/ext/ratatui_ruby/src/events.rs +115 -107
  50. data/ext/ratatui_ruby/src/lib.rs +15 -6
  51. data/ext/ratatui_ruby/src/rendering.rs +18 -1
  52. data/ext/ratatui_ruby/src/style.rs +2 -1
  53. data/ext/ratatui_ruby/src/terminal.rs +27 -24
  54. data/ext/ratatui_ruby/src/widgets/calendar.rs +82 -0
  55. data/ext/ratatui_ruby/src/widgets/canvas.rs +1 -2
  56. data/ext/ratatui_ruby/src/widgets/center.rs +0 -2
  57. data/ext/ratatui_ruby/src/widgets/chart.rs +260 -0
  58. data/ext/ratatui_ruby/src/widgets/clear.rs +37 -0
  59. data/ext/ratatui_ruby/src/widgets/cursor.rs +1 -1
  60. data/ext/ratatui_ruby/src/widgets/layout.rs +2 -1
  61. data/ext/ratatui_ruby/src/widgets/list.rs +44 -5
  62. data/ext/ratatui_ruby/src/widgets/mod.rs +3 -1
  63. data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
  64. data/ext/ratatui_ruby/src/widgets/paragraph.rs +10 -0
  65. data/ext/ratatui_ruby/src/widgets/table.rs +25 -6
  66. data/ext/ratatui_ruby/src/widgets/tabs.rs +2 -1
  67. data/lib/ratatui_ruby/dsl.rb +64 -0
  68. data/lib/ratatui_ruby/schema/calendar.rb +26 -0
  69. data/lib/ratatui_ruby/schema/chart.rb +81 -0
  70. data/lib/ratatui_ruby/schema/clear.rb +83 -0
  71. data/lib/ratatui_ruby/schema/list.rb +8 -2
  72. data/lib/ratatui_ruby/schema/paragraph.rb +7 -4
  73. data/lib/ratatui_ruby/schema/rect.rb +24 -0
  74. data/lib/ratatui_ruby/schema/table.rb +8 -2
  75. data/lib/ratatui_ruby/version.rb +1 -1
  76. data/lib/ratatui_ruby.rb +24 -2
  77. data/mise.toml +8 -0
  78. data/sig/ratatui_ruby/buffer.rbs +11 -0
  79. data/sig/ratatui_ruby/schema/calendar.rbs +13 -0
  80. data/sig/ratatui_ruby/schema/{line_chart.rbs → chart.rbs} +20 -1
  81. data/sig/ratatui_ruby/schema/list.rbs +4 -1
  82. data/sig/ratatui_ruby/schema/rect.rbs +14 -0
  83. data/tasks/bump/cargo_lockfile.rb +19 -0
  84. data/tasks/bump/changelog.rb +37 -0
  85. data/tasks/bump/comparison_links.rb +41 -0
  86. data/tasks/bump/header.rb +30 -0
  87. data/tasks/bump/history.rb +30 -0
  88. data/tasks/bump/manifest.rb +31 -0
  89. data/tasks/bump/ruby_gem.rb +35 -0
  90. data/tasks/bump/sem_ver.rb +34 -0
  91. data/tasks/bump/unreleased_section.rb +38 -0
  92. data/tasks/bump.rake +49 -0
  93. data/tasks/doc.rake +25 -0
  94. data/tasks/extension.rake +12 -0
  95. data/tasks/lint.rake +49 -0
  96. data/tasks/rdoc_config.rb +15 -0
  97. data/tasks/resources/build.yml.erb +65 -0
  98. data/tasks/resources/index.html.erb +38 -0
  99. data/tasks/resources/rubies.yml +7 -0
  100. data/tasks/sourcehut.rake +38 -0
  101. data/tasks/test.rake +31 -0
  102. data/tasks/website/index_page.rb +28 -0
  103. data/tasks/website/version.rb +117 -0
  104. data/tasks/website/version_menu.rb +68 -0
  105. data/tasks/website/versioned_documentation.rb +49 -0
  106. data/tasks/website/website.rb +53 -0
  107. data/tasks/website.rake +26 -0
  108. metadata +119 -28
  109. data/.build.yml +0 -34
  110. data/.ruby-version +0 -1
  111. data/CODE_OF_CONDUCT.md +0 -30
  112. data/CONTRIBUTING.md +0 -40
  113. data/docs/images/examples-stock_ticker.rb.png +0 -0
  114. data/ext/ratatui_ruby/src/widgets/linechart.rs +0 -154
  115. data/lib/ratatui_ruby/schema/line_chart.rb +0 -41
  116. /data/{docs → doc}/application_testing.md +0 -0
  117. /data/{docs → doc}/contributors/design/ruby_frontend.md +0 -0
  118. /data/{docs → doc}/contributors/design/rust_backend.md +0 -0
  119. /data/{docs → doc}/contributors/design.md +0 -0
  120. /data/{docs → doc}/images/examples-analytics.rb.png +0 -0
  121. /data/{docs → doc}/images/examples-box_demo.rb.png +0 -0
  122. /data/{docs → doc}/images/examples-dashboard.rb.png +0 -0
  123. /data/{docs → doc}/images/examples-login_form.rb.png +0 -0
  124. /data/{docs → doc}/images/examples-map_demo.rb.png +0 -0
  125. /data/{docs → doc}/images/examples-mouse_events.rb.png +0 -0
  126. /data/{docs → doc}/images/examples-scrollbar_demo.rb.png +0 -0
  127. /data/{docs → doc}/images/examples-system_monitor.rb.png +0 -0
@@ -14,5 +14,5 @@
14
14
 
15
15
  ## Documentation for Contributors
16
16
 
17
- - [Contributing Guidelines](../CONTRIBUTING.md)
17
+ - [Contributing Guidelines](https://man.sr.ht/~kerrick/ratatui_ruby/contributing.md)
18
18
  - [More Documentation for Contributors](./contributors/index.md)
@@ -11,7 +11,7 @@ Welcome to **ratatui_ruby**! This guide will help you get up and running with yo
11
11
  Add this line to your application's Gemfile:
12
12
 
13
13
  ```ruby
14
- gem 'ratatui_ruby'
14
+ gem "ratatui_ruby"
15
15
  ```
16
16
 
17
17
  And then execute:
@@ -32,10 +32,10 @@ Here is a "Hello World" application that demonstrates the core lifecycle of a **
32
32
 
33
33
  ```ruby
34
34
  require "ratatui_ruby"
35
-
35
+
36
36
  # 1. Initialize the terminal
37
37
  RatatuiRuby.init_terminal
38
-
38
+
39
39
  begin
40
40
  # The Main Loop
41
41
  loop do
@@ -43,17 +43,17 @@ begin
43
43
  # We define a Paragraph widget inside a Block with a title and borders.
44
44
  view = RatatuiRuby::Paragraph.new(
45
45
  text: "Hello, Ratatui! Press 'q' to quit.",
46
+ align: :center,
46
47
  block: RatatuiRuby::Block.new(
47
- title: "My First App",
48
+ title: "My Ruby TUI App",
48
49
  borders: [:all],
49
- border_style: "cyan"
50
- ),
51
- alignment: :center
50
+ border_color: "cyan"
51
+ )
52
52
  )
53
-
53
+
54
54
  # 3. Draw the UI
55
55
  RatatuiRuby.draw(view)
56
-
56
+
57
57
  # 4. Poll for events
58
58
  event = RatatuiRuby.poll_event
59
59
  if event && event[:type] == :key && event[:code] == "q"
@@ -66,6 +66,8 @@ ensure
66
66
  end
67
67
  ```
68
68
 
69
+ ![Basic Application Screenshot](./images/examples-quickstart_lifecycle.rb.png)
70
+
69
71
  ### How it works
70
72
 
71
73
  1. **`RatatuiRuby.init_terminal`**: Enters raw mode and switches to the alternate screen.
@@ -73,7 +75,42 @@ end
73
75
  3. **`RatatuiRuby.draw(view)`**: The Ruby UI tree is passed to the Rust backend, which renders it to the terminal.
74
76
  4. **`RatatuiRuby.poll_event`**: Checks for keyboard, mouse, or resize events.
75
77
  5. **`RatatuiRuby.restore_terminal`**: Crucial for leaving raw mode and returning the user to their shell properly. Always wrap your loop in a `begin...ensure` block to guarantee this runs.
76
- 6. **`sleep 0.05`**: In a real app, you'd want to control your frame rate to avoid consuming 100% CPU.
78
+
79
+ ### DSL
80
+
81
+ A small DSL is provided for convenience when writing scripts.
82
+
83
+ ```rb
84
+ require "ratatui_ruby"
85
+
86
+ # 1. Initialize the terminal, start the main loop, and ensure the terminal is restored.
87
+ RatatuiRuby.main_loop do |tui|
88
+ # 2. Create your UI with methods instead of classes.
89
+ view = tui.paragraph(
90
+ text: "Hello, Ratatui! Press 'q' to quit.",
91
+ align: :center,
92
+ block: tui.block(
93
+ title: "My Ruby TUI App",
94
+ borders: [:all],
95
+ border_color: "cyan"
96
+ )
97
+ )
98
+
99
+ # 3. Use RatatuiRuby methods, too.
100
+ tui.draw(view)
101
+ event = tui.poll_event
102
+
103
+ if event && event[:type] == :key && event[:code] == "q"
104
+ break
105
+ end
106
+ end
107
+ ```
108
+
109
+ #### How it works
110
+
111
+ 1. **`RatatuiRuby.main_loop`**: This helper method manages the entire terminal lifecycle for you. It initializes the terminal before the block starts and ensures `restore_terminal` is called when the block exits (even if an error occurs).
112
+ 2. **Widget Shorthand**: The block yields a special DSL object (here named `tui`). This object provides factory methods for every widget, allowing you to write `tui.paragraph(...)` instead of the more verbose `RatatuiRuby::Paragraph.new(...)`.
113
+ 3. **Method SHorthand**: The DSL object also provides aliases for module functions of `RatatuiRuby`, allowing you to write `tui.draw(...)` instead of the more verbose `RatatuiRuby::draw(...)`.
77
114
 
78
115
  ## Examples
79
116
 
@@ -89,11 +126,29 @@ A simple demonstration of `Block` and `Paragraph` widgets, reacting to arrow key
89
126
 
90
127
  ![Box Demo Screenshot](./images/examples-box_demo.rb.png)
91
128
 
129
+ ### [Calendar Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/calendar_demo.rb)
130
+ A simple demo application for the `Calendar` widget.
131
+
132
+ ![Calendar Screenshot](./images/examples-calendar_demo.rb.png)
133
+
134
+ ### [Chart Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/chart_demo.rb)
135
+ Demonstrates the `Chart` widget with both scatter and line datasets, including custom axes.
136
+
137
+ ![Chart Screenshot](./images/examples-chart_demo.rb.png)
138
+
139
+ ### [Custom Widget (Escape Hatch)](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/custom_widget.rb)
140
+ Demonstrates how to define a custom widget in pure Ruby using the `render(area, buffer)` escape hatch for low-level drawing.
141
+
142
+ ![Custom Widget Screenshot](./images/examples-custom_widget.rb.png)
143
+
92
144
  ### [Dashboard](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/dashboard.rb)
93
145
  Uses `Layout`, `List`, and `Paragraph` to create a classic sidebar-and-content interface.
94
146
 
95
147
  ![Dashboard Screenshot](./images/examples-dashboard.rb.png)
96
148
 
149
+ ### [List Styles](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/list_styles.rb)
150
+ Showcases advanced styling options for the `List` widget, including selection highlighting.
151
+
97
152
  ### [Login Form](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/login_form.rb)
98
153
  Shows how to use `Overlay`, `Center`, and `Cursor` to build a modal login form with text input.
99
154
 
@@ -109,13 +164,23 @@ Detailed plumbing of mouse events, including clicks, drags, and movement trackin
109
164
 
110
165
  ![Mouse Events Screenshot](./images/examples-mouse_events.rb.png)
111
166
 
167
+ ### [Popup Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/popup_demo.rb)
168
+ Demonstrates the `Clear` widget and how to prevent "style bleed" when rendering opaque popups over colored backgrounds.
169
+
170
+ ![Popup Demo Screenshot](./images/examples-popup_demo.rb.gif)
171
+
112
172
  ### [Scrollbar Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/scrollbar_demo.rb)
113
173
  A simple example of integrating the `Scrollbar` widget and handling mouse wheel events for scrolling.
114
174
 
115
175
  ![Scrollbar Demo Screenshot](./images/examples-scrollbar_demo.rb.png)
116
176
 
177
+ ### [Scroll Text](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/scroll_text.rb)
178
+ Demonstrates the `Paragraph` widget's scroll functionality, allowing navigation through long text content using arrow keys for both horizontal and vertical scrolling.
179
+
180
+ ![Scroll Text Screenshot](./images/examples-scroll_text.rb.png)
181
+
117
182
  ### [Stock Ticker](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/stock_ticker.rb)
118
- Utilizes `Sparkline` and `LineChart` widgets to visualize real-time (simulated) data.
183
+ Utilizes `Sparkline` and `Chart` widgets to visualize real-time (simulated) data.
119
184
 
120
185
  ![Stock Ticker Screenshot](./images/examples-stock_ticker.rb.png)
121
186
 
@@ -124,3 +189,8 @@ Combines `Table` and `Gauge` widgets in a vertical layout to create a functional
124
189
 
125
190
  ![System Monitor Screenshot](./images/examples-system_monitor.rb.png)
126
191
 
192
+ ### [Table Select](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/table_select.rb)
193
+ Demonstrates interactive row selection in the `Table` widget with keyboard navigation, highlighting selected rows with custom styles and symbols.
194
+
195
+ ![Table Select Screenshot](./images/examples-table_select.rb.png)
196
+
@@ -3,7 +3,8 @@
3
3
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
4
  # SPDX-License-Identifier: AGPL-3.0-or-later
5
5
 
6
- require_relative "../lib/ratatui_ruby"
6
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
+ require "ratatui_ruby"
7
8
 
8
9
  # Analytics Dashboard Example
9
10
  # Demonstrates Tabs and BarChart widgets.
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
+ require "ratatui_ruby"
8
+
9
+ # A demo application for the Calendar widget.
10
+ module CalendarDemo
11
+ def self.run
12
+ RatatuiRuby.init_terminal
13
+
14
+ loop do
15
+ now = Time.now
16
+ calendar = RatatuiRuby::Calendar.new(
17
+ year: now.year,
18
+ month: now.month,
19
+ header_style: RatatuiRuby::Style.new(fg: "yellow", modifiers: [:bold]),
20
+ block: RatatuiRuby::Block.new(title: " Calendar (q = quit) ", borders: [:all])
21
+ )
22
+
23
+ # Constrain the calendar to 24x10 characters
24
+ view = RatatuiRuby::Layout.new(
25
+ direction: :vertical,
26
+ constraints: [
27
+ RatatuiRuby::Constraint.length(10),
28
+ RatatuiRuby::Constraint.min(0),
29
+ ],
30
+ children: [
31
+ RatatuiRuby::Layout.new(
32
+ direction: :horizontal,
33
+ constraints: [
34
+ RatatuiRuby::Constraint.length(24),
35
+ RatatuiRuby::Constraint.min(0),
36
+ ],
37
+ children: [calendar, nil],
38
+ ),
39
+ nil,
40
+ ],
41
+ )
42
+
43
+ RatatuiRuby.draw(view)
44
+
45
+ event = RatatuiRuby.poll_event
46
+ break if event && event[:type] == :key && event[:code] == "q"
47
+
48
+ sleep 0.1
49
+ end
50
+ ensure
51
+ RatatuiRuby.restore_terminal
52
+ end
53
+ end
54
+
55
+ CalendarDemo.run if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
+ require "ratatui_ruby"
8
+
9
+ # Chart Demo
10
+ # Demonstrates Scatter and Line datasets in a single Chart.
11
+ class ChartDemoApp
12
+ def run
13
+ RatatuiRuby.init_terminal
14
+ begin
15
+ loop do
16
+ render
17
+ break if handle_input == :quit
18
+ sleep 0.1
19
+ end
20
+ ensure
21
+ RatatuiRuby.restore_terminal
22
+ end
23
+ end
24
+
25
+ def render
26
+ # Scatter data: Random points
27
+ scatter_data = Array.new(20) { [rand(0.0..10.0), rand(-1.0..1.0)] }
28
+
29
+ # Line data: Sine wave
30
+ line_data = (0..100).map do |i|
31
+ x = i / 10.0
32
+ [x, Math.sin(x)]
33
+ end
34
+
35
+ datasets = [
36
+ RatatuiRuby::Dataset.new(
37
+ name: "Scatter",
38
+ data: scatter_data,
39
+ color: "red",
40
+ marker: :dot,
41
+ graph_type: :scatter,
42
+ ),
43
+ RatatuiRuby::Dataset.new(
44
+ name: "Line",
45
+ data: line_data,
46
+ color: "green",
47
+ marker: :braille,
48
+ graph_type: :line,
49
+ ),
50
+ ]
51
+
52
+ chart = RatatuiRuby::Chart.new(
53
+ datasets:,
54
+ x_axis: RatatuiRuby::Axis.new(
55
+ title: "Time",
56
+ bounds: [0.0, 10.0],
57
+ labels: %w[0 5 10],
58
+ style: RatatuiRuby::Style.new(fg: :yellow),
59
+ ),
60
+ y_axis: RatatuiRuby::Axis.new(
61
+ title: "Amplitude",
62
+ bounds: [-1.0, 1.0],
63
+ labels: %w[-1 0 1],
64
+ style: RatatuiRuby::Style.new(fg: :cyan),
65
+ ),
66
+ block: RatatuiRuby::Block.new(
67
+ title: "Chart Demo (Q to quit)",
68
+ borders: [:all],
69
+ ),
70
+ )
71
+
72
+ RatatuiRuby.draw(chart)
73
+ end
74
+
75
+ def handle_input
76
+ event = RatatuiRuby.poll_event
77
+ return nil unless event
78
+
79
+ return :quit if event[:type] == :key && event[:code] == "q"
80
+ nil
81
+ end
82
+ end
83
+
84
+ ChartDemoApp.new.run if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
+ require "ratatui_ruby"
8
+
9
+ # A custom widget that draws a diagonal line.
10
+ class DiagonalWidget
11
+ def render(area, buffer)
12
+ # Draw a diagonal line within the area
13
+ (0..10).each do |i|
14
+ next if area.x + i >= area.x + area.width || area.y + i >= area.y + area.height
15
+
16
+ buffer.set_string(
17
+ area.x + i,
18
+ area.y + i,
19
+ "\\",
20
+ RatatuiRuby::Style.new(fg: :red, modifiers: [:bold])
21
+ )
22
+ end
23
+ end
24
+ end
25
+
26
+ RatatuiRuby.main_loop do |tui|
27
+ tui.draw(
28
+ RatatuiRuby::Layout.new(
29
+ direction: :vertical,
30
+ constraints: [
31
+ RatatuiRuby::Constraint.percentage(50),
32
+ RatatuiRuby::Constraint.percentage(50),
33
+ ],
34
+ children: [
35
+ RatatuiRuby::Paragraph.new(text: "Above custom widget"),
36
+ DiagonalWidget.new,
37
+ ]
38
+ )
39
+ )
40
+
41
+ event = RatatuiRuby.poll_event
42
+ break if event && event[:type] == :key && event[:code] == "q"
43
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
+ require "ratatui_ruby"
8
+
9
+ # Styled List Example
10
+ # Demonstrates advanced styling options for the List widget.
11
+ class ListStylesApp
12
+ attr_reader :selected_index
13
+
14
+ def initialize
15
+ @items = ["Item 1", "Item 2", "Item 3"]
16
+ @selected_index = 0
17
+ end
18
+
19
+ def run
20
+ RatatuiRuby.init_terminal
21
+ begin
22
+ loop do
23
+ render
24
+ break if handle_input == :quit
25
+ sleep 0.05
26
+ end
27
+ ensure
28
+ RatatuiRuby.restore_terminal
29
+ end
30
+ end
31
+
32
+ def render
33
+ RatatuiRuby.draw(
34
+ RatatuiRuby::List.new(
35
+ items: @items,
36
+ selected_index: @selected_index,
37
+ style: RatatuiRuby::Style.new(fg: :white, bg: :black),
38
+ highlight_style: RatatuiRuby::Style.new(fg: :blue, bg: :white, modifiers: [:bold]),
39
+ highlight_symbol: ">> ",
40
+ block: RatatuiRuby::Block.new(
41
+ title: "Styled List (Up/Down to move, Q to quit)",
42
+ borders: [:all]
43
+ )
44
+ )
45
+ )
46
+ end
47
+
48
+ def handle_input
49
+ event = RatatuiRuby.poll_event
50
+ return nil unless event
51
+
52
+ if event[:type] == :key
53
+ case event[:code]
54
+ when "up"
55
+ @selected_index = (@selected_index - 1) % @items.size
56
+ when "down"
57
+ @selected_index = (@selected_index + 1) % @items.size
58
+ when "q"
59
+ return :quit
60
+ end
61
+ end
62
+ nil
63
+ end
64
+ end
65
+
66
+ ListStylesApp.new.run if __FILE__ == $PROGRAM_NAME
@@ -3,7 +3,8 @@
3
3
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
4
  # SPDX-License-Identifier: AGPL-3.0-or-later
5
5
 
6
- require_relative "../lib/ratatui_ruby"
6
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
+ require "ratatui_ruby"
7
8
 
8
9
  class LoginFormApp
9
10
  PREFIX = "Enter Username: [ "
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
+ require "ratatui_ruby"
8
+
9
+ # Popup Demo Example
10
+ # Demonstrates the Clear widget for creating opaque popups.
11
+
12
+ class PopupDemo
13
+ def initialize
14
+ @clear_enabled = false
15
+ end
16
+
17
+ def run
18
+ RatatuiRuby.init_terminal
19
+ begin
20
+ loop do
21
+ render
22
+ break if handle_input == :quit
23
+ sleep 0.05
24
+ end
25
+ ensure
26
+ RatatuiRuby.restore_terminal
27
+ end
28
+ end
29
+
30
+ def render
31
+ # 1. Background: Loud Red Background
32
+ # This demonstrates "Style Bleed" where the background color persists
33
+ # unless explicitly cleared or overwritten.
34
+ background = RatatuiRuby::Paragraph.new(
35
+ text: "BACKGROUND RED " * 100,
36
+ style: RatatuiRuby::Style.new(bg: :red, fg: :white),
37
+ wrap: true
38
+ )
39
+
40
+ # 2. Popup Content: No specific background set (Style.default)
41
+ # Without Clear, this will "inherit" the red background from underneath.
42
+ popup_text = if @clear_enabled
43
+ "✓ Clear is ENABLED\n\nResets background to default\n(Usually Black/Transparent)\n\nPress Space to toggle"
44
+ else
45
+ "✗ Clear is DISABLED\n\nStyle Bleed: Popup is RED!\n(Inherits background style)\n\nPress Space to toggle"
46
+ end
47
+
48
+ popup_content = RatatuiRuby::Paragraph.new(
49
+ text: popup_text,
50
+ align: :center,
51
+ block: RatatuiRuby::Block.new(
52
+ title: "Popup Demo (Press 'q' to quit)",
53
+ borders: [:all]
54
+ )
55
+ )
56
+
57
+ # Build the UI with or without Clear
58
+ if @clear_enabled
59
+ # With Clear: Resets the style in the popup area before rendering content
60
+ ui = RatatuiRuby::Overlay.new(
61
+ layers: [
62
+ background,
63
+ RatatuiRuby::Center.new(
64
+ child: RatatuiRuby::Overlay.new(
65
+ layers: [
66
+ RatatuiRuby::Clear.new,
67
+ popup_content
68
+ ]
69
+ ),
70
+ width_percent: 60,
71
+ height_percent: 50
72
+ )
73
+ ]
74
+ )
75
+ else
76
+ # Without Clear: Background style (RED) bleeds through the popup
77
+ ui = RatatuiRuby::Overlay.new(
78
+ layers: [
79
+ background,
80
+ RatatuiRuby::Center.new(
81
+ child: popup_content,
82
+ width_percent: 60,
83
+ height_percent: 50
84
+ )
85
+ ]
86
+ )
87
+ end
88
+
89
+ RatatuiRuby.draw(ui)
90
+ end
91
+
92
+ def handle_input
93
+ event = RatatuiRuby.poll_event
94
+ if event
95
+ case event[:code]
96
+ when "q"
97
+ :quit
98
+ when " "
99
+ @clear_enabled = !@clear_enabled
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ PopupDemo.new.run if __FILE__ == $0
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
+
8
+ require "ratatui_ruby"
9
+
10
+ # 1. Initialize the terminal, start the main loop, and ensure the terminal is restored.
11
+ RatatuiRuby.main_loop do |tui|
12
+ # 2. Create your UI with methods instead of classes.
13
+ view = tui.paragraph(
14
+ text: "Hello, Ratatui! Press 'q' to quit.",
15
+ align: :center,
16
+ block: tui.block(
17
+ title: "My Ruby TUI App",
18
+ borders: [:all],
19
+ border_color: "cyan"
20
+ )
21
+ )
22
+
23
+ # 3. Use RatatuiRuby methods, too.
24
+ tui.draw(view)
25
+ event = tui.poll_event
26
+
27
+ if event && event[:type] == :key && event[:code] == "q"
28
+ break
29
+ end
30
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
+
8
+ require "ratatui_ruby"
9
+
10
+ # 1. Initialize the terminal
11
+ RatatuiRuby.init_terminal
12
+
13
+ begin
14
+ # The Main Loop
15
+ loop do
16
+ # 2. Create your UI (Immediate Mode)
17
+ # We define a Paragraph widget inside a Block with a title and borders.
18
+ view = RatatuiRuby::Paragraph.new(
19
+ text: "Hello, Ratatui! Press 'q' to quit.",
20
+ align: :center,
21
+ block: RatatuiRuby::Block.new(
22
+ title: "My Ruby TUI App",
23
+ borders: [:all],
24
+ border_color: "cyan"
25
+ )
26
+ )
27
+
28
+ # 3. Draw the UI
29
+ RatatuiRuby.draw(view)
30
+
31
+ # 4. Poll for events
32
+ event = RatatuiRuby.poll_event
33
+ if event && event[:type] == :key && event[:code] == "q"
34
+ break
35
+ end
36
+ end
37
+ ensure
38
+ # 5. Restore the terminal to its original state
39
+ RatatuiRuby.restore_terminal
40
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
+
8
+ require "ratatui_ruby"
9
+ RatatuiRuby.main_loop do |tui|
10
+ tui.draw \
11
+ tui.paragraph \
12
+ text: "Hello, Ratatui! Press 'q' to quit.",
13
+ align: :center,
14
+ block: tui.block(
15
+ title: "My Ruby TUI App",
16
+ borders: [:all],
17
+ border_color: "cyan"
18
+ )
19
+ event = tui.poll_event
20
+ break if event && event[:type] == :key && event[:code] == "q"
21
+ end