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.
- checksums.yaml +4 -4
- data/.builds/ruby-3.2.yml +52 -0
- data/.builds/ruby-3.3.yml +52 -0
- data/.builds/ruby-3.4.yml +52 -0
- data/.builds/ruby-4.0.0.yml +53 -0
- data/.pre-commit-config.yaml +9 -2
- data/AGENTS.md +53 -5
- data/CHANGELOG.md +51 -1
- data/README.md +38 -18
- data/REUSE.toml +5 -0
- data/Rakefile +3 -100
- data/{docs → doc}/contributors/index.md +2 -1
- data/doc/custom.css +8 -0
- data/doc/images/examples-calendar_demo.rb.png +0 -0
- data/doc/images/examples-chart_demo.rb.png +0 -0
- data/doc/images/examples-custom_widget.rb.png +0 -0
- data/doc/images/examples-list_styles.rb.png +0 -0
- data/doc/images/examples-popup_demo.rb.gif +0 -0
- data/doc/images/examples-quickstart_lifecycle.rb.png +0 -0
- data/doc/images/examples-scroll_text.rb.png +0 -0
- data/doc/images/examples-stock_ticker.rb.png +0 -0
- data/doc/images/examples-table_select.rb.png +0 -0
- data/{docs → doc}/index.md +1 -1
- data/{docs → doc}/quickstart.md +81 -11
- data/examples/analytics.rb +2 -1
- data/examples/calendar_demo.rb +55 -0
- data/examples/chart_demo.rb +84 -0
- data/examples/custom_widget.rb +43 -0
- data/examples/list_styles.rb +66 -0
- data/examples/login_form.rb +2 -1
- data/examples/popup_demo.rb +105 -0
- data/examples/quickstart_dsl.rb +30 -0
- data/examples/quickstart_lifecycle.rb +40 -0
- data/examples/readme_usage.rb +21 -0
- data/examples/scroll_text.rb +74 -0
- data/examples/stock_ticker.rb +13 -5
- data/examples/system_monitor.rb +2 -1
- data/examples/table_select.rb +70 -0
- data/examples/test_calendar_demo.rb +66 -0
- data/examples/test_list_styles.rb +61 -0
- data/examples/test_popup_demo.rb +62 -0
- data/examples/test_scroll_text.rb +130 -0
- data/examples/test_table_select.rb +37 -0
- data/ext/ratatui_ruby/.cargo/config.toml +5 -0
- data/ext/ratatui_ruby/Cargo.lock +260 -50
- data/ext/ratatui_ruby/Cargo.toml +5 -4
- data/ext/ratatui_ruby/extconf.rb +1 -1
- data/ext/ratatui_ruby/src/buffer.rs +54 -0
- data/ext/ratatui_ruby/src/events.rs +115 -107
- data/ext/ratatui_ruby/src/lib.rs +15 -6
- data/ext/ratatui_ruby/src/rendering.rs +18 -1
- data/ext/ratatui_ruby/src/style.rs +2 -1
- data/ext/ratatui_ruby/src/terminal.rs +27 -24
- data/ext/ratatui_ruby/src/widgets/calendar.rs +82 -0
- data/ext/ratatui_ruby/src/widgets/canvas.rs +1 -2
- data/ext/ratatui_ruby/src/widgets/center.rs +0 -2
- data/ext/ratatui_ruby/src/widgets/chart.rs +260 -0
- data/ext/ratatui_ruby/src/widgets/clear.rs +37 -0
- data/ext/ratatui_ruby/src/widgets/cursor.rs +1 -1
- data/ext/ratatui_ruby/src/widgets/layout.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/list.rs +44 -5
- data/ext/ratatui_ruby/src/widgets/mod.rs +3 -1
- data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/paragraph.rs +10 -0
- data/ext/ratatui_ruby/src/widgets/table.rs +25 -6
- data/ext/ratatui_ruby/src/widgets/tabs.rs +2 -1
- data/lib/ratatui_ruby/dsl.rb +64 -0
- data/lib/ratatui_ruby/schema/calendar.rb +26 -0
- data/lib/ratatui_ruby/schema/chart.rb +81 -0
- data/lib/ratatui_ruby/schema/clear.rb +83 -0
- data/lib/ratatui_ruby/schema/list.rb +8 -2
- data/lib/ratatui_ruby/schema/paragraph.rb +7 -4
- data/lib/ratatui_ruby/schema/rect.rb +24 -0
- data/lib/ratatui_ruby/schema/table.rb +8 -2
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby.rb +24 -2
- data/mise.toml +8 -0
- data/sig/ratatui_ruby/buffer.rbs +11 -0
- data/sig/ratatui_ruby/schema/calendar.rbs +13 -0
- data/sig/ratatui_ruby/schema/{line_chart.rbs → chart.rbs} +20 -1
- data/sig/ratatui_ruby/schema/list.rbs +4 -1
- data/sig/ratatui_ruby/schema/rect.rbs +14 -0
- data/tasks/bump/cargo_lockfile.rb +19 -0
- data/tasks/bump/changelog.rb +37 -0
- data/tasks/bump/comparison_links.rb +41 -0
- data/tasks/bump/header.rb +30 -0
- data/tasks/bump/history.rb +30 -0
- data/tasks/bump/manifest.rb +31 -0
- data/tasks/bump/ruby_gem.rb +35 -0
- data/tasks/bump/sem_ver.rb +34 -0
- data/tasks/bump/unreleased_section.rb +38 -0
- data/tasks/bump.rake +49 -0
- data/tasks/doc.rake +25 -0
- data/tasks/extension.rake +12 -0
- data/tasks/lint.rake +49 -0
- data/tasks/rdoc_config.rb +15 -0
- data/tasks/resources/build.yml.erb +65 -0
- data/tasks/resources/index.html.erb +38 -0
- data/tasks/resources/rubies.yml +7 -0
- data/tasks/sourcehut.rake +38 -0
- data/tasks/test.rake +31 -0
- data/tasks/website/index_page.rb +28 -0
- data/tasks/website/version.rb +117 -0
- data/tasks/website/version_menu.rb +68 -0
- data/tasks/website/versioned_documentation.rb +49 -0
- data/tasks/website/website.rb +53 -0
- data/tasks/website.rake +26 -0
- metadata +119 -28
- data/.build.yml +0 -34
- data/.ruby-version +0 -1
- data/CODE_OF_CONDUCT.md +0 -30
- data/CONTRIBUTING.md +0 -40
- data/docs/images/examples-stock_ticker.rb.png +0 -0
- data/ext/ratatui_ruby/src/widgets/linechart.rs +0 -154
- data/lib/ratatui_ruby/schema/line_chart.rb +0 -41
- /data/{docs → doc}/application_testing.md +0 -0
- /data/{docs → doc}/contributors/design/ruby_frontend.md +0 -0
- /data/{docs → doc}/contributors/design/rust_backend.md +0 -0
- /data/{docs → doc}/contributors/design.md +0 -0
- /data/{docs → doc}/images/examples-analytics.rb.png +0 -0
- /data/{docs → doc}/images/examples-box_demo.rb.png +0 -0
- /data/{docs → doc}/images/examples-dashboard.rb.png +0 -0
- /data/{docs → doc}/images/examples-login_form.rb.png +0 -0
- /data/{docs → doc}/images/examples-map_demo.rb.png +0 -0
- /data/{docs → doc}/images/examples-mouse_events.rb.png +0 -0
- /data/{docs → doc}/images/examples-scrollbar_demo.rb.png +0 -0
- /data/{docs → doc}/images/examples-system_monitor.rb.png +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/{docs → doc}/index.md
RENAMED
data/{docs → doc}/quickstart.md
RENAMED
|
@@ -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
|
|
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
|
|
48
|
+
title: "My Ruby TUI App",
|
|
48
49
|
borders: [:all],
|
|
49
|
-
|
|
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
|
+

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

|
|
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
|
+

|
|
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
|
+

|
|
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
|
+

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

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

|
|
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
|
+

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

|
|
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
|
+

|
|
181
|
+
|
|
117
182
|
### [Stock Ticker](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/stock_ticker.rb)
|
|
118
|
-
Utilizes `Sparkline` and `
|
|
183
|
+
Utilizes `Sparkline` and `Chart` widgets to visualize real-time (simulated) data.
|
|
119
184
|
|
|
120
185
|

|
|
121
186
|
|
|
@@ -124,3 +189,8 @@ Combines `Table` and `Gauge` widgets in a vertical layout to create a functional
|
|
|
124
189
|
|
|
125
190
|

|
|
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
|
+

|
|
196
|
+
|
data/examples/analytics.rb
CHANGED
|
@@ -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
|
-
|
|
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
|
data/examples/login_form.rb
CHANGED
|
@@ -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
|
-
|
|
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
|