ratatui_ruby 1.1.0 → 1.1.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.
- checksums.yaml +4 -4
- data/ext/ratatui_ruby/Cargo.lock +1 -1
- data/ext/ratatui_ruby/Cargo.toml +1 -1
- data/lib/ratatui_ruby/version.rb +1 -1
- metadata +1 -255
- data/.builds/ruby-3.2.yml +0 -54
- data/.builds/ruby-3.3.yml +0 -54
- data/.builds/ruby-3.4.yml +0 -54
- data/.builds/ruby-4.0.0.yml +0 -54
- data/.pre-commit-config.yaml +0 -16
- data/.rubocop.yml +0 -10
- data/AGENTS.md +0 -147
- data/CHANGELOG.md +0 -736
- data/README.md +0 -187
- data/README.rdoc +0 -302
- data/Rakefile +0 -11
- data/Steepfile +0 -50
- data/doc/concepts/application_architecture.md +0 -321
- data/doc/concepts/application_testing.md +0 -193
- data/doc/concepts/async.md +0 -190
- data/doc/concepts/custom_widgets.md +0 -247
- data/doc/concepts/debugging.md +0 -401
- data/doc/concepts/event_handling.md +0 -162
- data/doc/concepts/interactive_design.md +0 -146
- data/doc/contributors/auditing/parity.md +0 -239
- data/doc/contributors/design/ruby_frontend.md +0 -448
- data/doc/contributors/design/rust_backend.md +0 -434
- data/doc/contributors/design.md +0 -11
- data/doc/contributors/developing_examples.md +0 -400
- data/doc/contributors/documentation_style.md +0 -121
- data/doc/contributors/index.md +0 -21
- data/doc/contributors/releasing.md +0 -215
- data/doc/contributors/todo/align/api_completeness_audit-finished.md +0 -381
- data/doc/contributors/todo/align/api_completeness_audit-unfinished.md +0 -200
- data/doc/contributors/todo/align/term.md +0 -351
- data/doc/contributors/todo/align/terminal.md +0 -647
- data/doc/contributors/todo/future_work.md +0 -169
- data/doc/contributors/upstream_requests/paragraph_span_rects.md +0 -259
- data/doc/contributors/upstream_requests/tab_rects.md +0 -173
- data/doc/contributors/upstream_requests/title_rects.md +0 -132
- data/doc/custom.css +0 -22
- data/doc/getting_started/quickstart.md +0 -291
- data/doc/getting_started/why.md +0 -93
- data/doc/images/app_all_events.png +0 -0
- data/doc/images/app_cli_rich_moments.gif +0 -0
- data/doc/images/app_color_picker.png +0 -0
- data/doc/images/app_debugging_showcase.gif +0 -0
- data/doc/images/app_debugging_showcase.png +0 -0
- data/doc/images/app_external_editor.gif +0 -0
- data/doc/images/app_login_form.png +0 -0
- data/doc/images/app_stateful_interaction.png +0 -0
- data/doc/images/verify_quickstart_dsl.png +0 -0
- data/doc/images/verify_quickstart_layout.png +0 -0
- data/doc/images/verify_quickstart_lifecycle.png +0 -0
- data/doc/images/verify_readme_usage.png +0 -0
- data/doc/images/widget_barchart.png +0 -0
- data/doc/images/widget_block.png +0 -0
- data/doc/images/widget_box.png +0 -0
- data/doc/images/widget_calendar.png +0 -0
- data/doc/images/widget_canvas.png +0 -0
- data/doc/images/widget_cell.png +0 -0
- data/doc/images/widget_center.png +0 -0
- data/doc/images/widget_chart.png +0 -0
- data/doc/images/widget_gauge.png +0 -0
- data/doc/images/widget_layout_split.png +0 -0
- data/doc/images/widget_line_gauge.png +0 -0
- data/doc/images/widget_list.png +0 -0
- data/doc/images/widget_map.png +0 -0
- data/doc/images/widget_overlay.png +0 -0
- data/doc/images/widget_popup.png +0 -0
- data/doc/images/widget_ratatui_logo.png +0 -0
- data/doc/images/widget_ratatui_mascot.png +0 -0
- data/doc/images/widget_rect.png +0 -0
- data/doc/images/widget_render.png +0 -0
- data/doc/images/widget_rich_text.png +0 -0
- data/doc/images/widget_scroll_text.png +0 -0
- data/doc/images/widget_scrollbar.png +0 -0
- data/doc/images/widget_sparkline.png +0 -0
- data/doc/images/widget_style_colors.png +0 -0
- data/doc/images/widget_table.png +0 -0
- data/doc/images/widget_tabs.png +0 -0
- data/doc/images/widget_text_width.png +0 -0
- data/doc/index.md +0 -34
- data/doc/troubleshooting/async.md +0 -4
- data/doc/troubleshooting/terminal_limitations.md +0 -131
- data/doc/troubleshooting/tui_output.md +0 -197
- data/examples/app_all_events/README.md +0 -114
- data/examples/app_all_events/app.rb +0 -98
- data/examples/app_all_events/model/app_model.rb +0 -159
- data/examples/app_all_events/model/event_color_cycle.rb +0 -43
- data/examples/app_all_events/model/event_entry.rb +0 -94
- data/examples/app_all_events/model/msg.rb +0 -39
- data/examples/app_all_events/model/timestamp.rb +0 -56
- data/examples/app_all_events/update.rb +0 -75
- data/examples/app_all_events/view/app_view.rb +0 -80
- data/examples/app_all_events/view/controls_view.rb +0 -54
- data/examples/app_all_events/view/counts_view.rb +0 -61
- data/examples/app_all_events/view/live_view.rb +0 -72
- data/examples/app_all_events/view/log_view.rb +0 -57
- data/examples/app_all_events/view.rb +0 -9
- data/examples/app_cli_rich_moments/README.md +0 -81
- data/examples/app_cli_rich_moments/app.rb +0 -189
- data/examples/app_color_picker/README.md +0 -156
- data/examples/app_color_picker/app.rb +0 -76
- data/examples/app_color_picker/clipboard.rb +0 -86
- data/examples/app_color_picker/color.rb +0 -193
- data/examples/app_color_picker/controls.rb +0 -92
- data/examples/app_color_picker/copy_dialog.rb +0 -168
- data/examples/app_color_picker/export_pane.rb +0 -128
- data/examples/app_color_picker/harmony.rb +0 -58
- data/examples/app_color_picker/input.rb +0 -176
- data/examples/app_color_picker/main_container.rb +0 -180
- data/examples/app_color_picker/palette.rb +0 -111
- data/examples/app_debugging_showcase/README.md +0 -119
- data/examples/app_debugging_showcase/app.rb +0 -318
- data/examples/app_external_editor/README.md +0 -62
- data/examples/app_external_editor/app.rb +0 -344
- data/examples/app_login_form/README.md +0 -58
- data/examples/app_login_form/app.rb +0 -109
- data/examples/app_stateful_interaction/README.md +0 -35
- data/examples/app_stateful_interaction/app.rb +0 -328
- data/examples/timeout_demo.rb +0 -45
- data/examples/verify_quickstart_dsl/README.md +0 -55
- data/examples/verify_quickstart_dsl/app.rb +0 -49
- data/examples/verify_quickstart_layout/README.md +0 -77
- data/examples/verify_quickstart_layout/app.rb +0 -73
- data/examples/verify_quickstart_lifecycle/README.md +0 -68
- data/examples/verify_quickstart_lifecycle/app.rb +0 -62
- data/examples/verify_readme_usage/README.md +0 -49
- data/examples/verify_readme_usage/app.rb +0 -42
- data/examples/verify_website_managed/README.md +0 -48
- data/examples/verify_website_managed/app.rb +0 -36
- data/examples/verify_website_menu/README.md +0 -60
- data/examples/verify_website_menu/app.rb +0 -84
- data/examples/verify_website_spinner/README.md +0 -44
- data/examples/verify_website_spinner/app.rb +0 -34
- data/examples/widget_barchart/README.md +0 -58
- data/examples/widget_barchart/app.rb +0 -240
- data/examples/widget_block/README.md +0 -44
- data/examples/widget_block/app.rb +0 -258
- data/examples/widget_box/README.md +0 -54
- data/examples/widget_box/app.rb +0 -255
- data/examples/widget_calendar/README.md +0 -48
- data/examples/widget_calendar/app.rb +0 -115
- data/examples/widget_canvas/README.md +0 -31
- data/examples/widget_canvas/app.rb +0 -130
- data/examples/widget_cell/README.md +0 -45
- data/examples/widget_cell/app.rb +0 -112
- data/examples/widget_center/README.md +0 -33
- data/examples/widget_center/app.rb +0 -118
- data/examples/widget_chart/README.md +0 -50
- data/examples/widget_chart/app.rb +0 -220
- data/examples/widget_gauge/README.md +0 -50
- data/examples/widget_gauge/app.rb +0 -229
- data/examples/widget_layout_split/README.md +0 -53
- data/examples/widget_layout_split/app.rb +0 -260
- data/examples/widget_line_gauge/README.md +0 -50
- data/examples/widget_line_gauge/app.rb +0 -219
- data/examples/widget_list/README.md +0 -58
- data/examples/widget_list/app.rb +0 -382
- data/examples/widget_map/README.md +0 -48
- data/examples/widget_map/app.rb +0 -95
- data/examples/widget_overlay/README.md +0 -45
- data/examples/widget_overlay/app.rb +0 -250
- data/examples/widget_popup/README.md +0 -45
- data/examples/widget_popup/app.rb +0 -106
- data/examples/widget_ratatui_logo/README.md +0 -43
- data/examples/widget_ratatui_logo/app.rb +0 -104
- data/examples/widget_ratatui_mascot/README.md +0 -43
- data/examples/widget_ratatui_mascot/app.rb +0 -95
- data/examples/widget_rect/README.md +0 -53
- data/examples/widget_rect/app.rb +0 -222
- data/examples/widget_render/README.md +0 -46
- data/examples/widget_render/app.rb +0 -186
- data/examples/widget_render/app.rbs +0 -41
- data/examples/widget_rich_text/README.md +0 -44
- data/examples/widget_rich_text/app.rb +0 -193
- data/examples/widget_scroll_text/README.md +0 -46
- data/examples/widget_scroll_text/app.rb +0 -109
- data/examples/widget_scrollbar/README.md +0 -46
- data/examples/widget_scrollbar/app.rb +0 -155
- data/examples/widget_sparkline/README.md +0 -51
- data/examples/widget_sparkline/app.rb +0 -277
- data/examples/widget_style_colors/README.md +0 -43
- data/examples/widget_style_colors/app.rb +0 -83
- data/examples/widget_table/README.md +0 -57
- data/examples/widget_table/app.rb +0 -285
- data/examples/widget_tabs/README.md +0 -50
- data/examples/widget_tabs/app.rb +0 -183
- data/examples/widget_text_width/README.md +0 -44
- data/examples/widget_text_width/app.rb +0 -117
- data/migrate_to_buffer.rb +0 -145
- data/mise.toml +0 -8
- data/tasks/autodoc/examples.rb +0 -87
- data/tasks/autodoc/member.rb +0 -58
- data/tasks/autodoc/name.rb +0 -21
- data/tasks/autodoc.rake +0 -21
- data/tasks/bump/bump_workflow.rb +0 -49
- data/tasks/bump/cargo_lockfile.rb +0 -21
- data/tasks/bump/changelog.rb +0 -104
- data/tasks/bump/header.rb +0 -32
- data/tasks/bump/history.rb +0 -32
- data/tasks/bump/links.rb +0 -69
- data/tasks/bump/manifest.rb +0 -33
- data/tasks/bump/patch_release.rb +0 -19
- data/tasks/bump/release_branch.rb +0 -17
- data/tasks/bump/release_from_trunk.rb +0 -49
- data/tasks/bump/repository.rb +0 -54
- data/tasks/bump/ruby_gem.rb +0 -29
- data/tasks/bump/sem_ver.rb +0 -44
- data/tasks/bump/unreleased_section.rb +0 -73
- data/tasks/bump.rake +0 -61
- data/tasks/doc/documentation.rb +0 -59
- data/tasks/doc/link/file_url.rb +0 -30
- data/tasks/doc/link/relative_path.rb +0 -61
- data/tasks/doc/link/web_url.rb +0 -55
- data/tasks/doc/link.rb +0 -52
- data/tasks/doc/link_audit.rb +0 -116
- data/tasks/doc/problem.rb +0 -40
- data/tasks/doc/source_file.rb +0 -93
- data/tasks/doc.rake +0 -905
- data/tasks/example_viewer.html.erb +0 -172
- data/tasks/extension.rake +0 -14
- data/tasks/license/headers_md.rb +0 -223
- data/tasks/license/headers_rb.rb +0 -210
- data/tasks/license/license_utils.rb +0 -130
- data/tasks/license/snippets_md.rb +0 -315
- data/tasks/license/snippets_rdoc.rb +0 -150
- data/tasks/license.rake +0 -91
- data/tasks/lint.rake +0 -170
- data/tasks/rbs_predicates/predicate_catalog.rb +0 -52
- data/tasks/rbs_predicates/predicate_tests.rb +0 -124
- data/tasks/rbs_predicates/rbs_signature.rb +0 -63
- data/tasks/rbs_predicates.rake +0 -31
- data/tasks/rdoc_config.rb +0 -29
- data/tasks/resources/build.yml.erb +0 -60
- data/tasks/resources/index.html.erb +0 -141
- data/tasks/resources/rubies.yml +0 -7
- data/tasks/sourcehut.rake +0 -110
- data/tasks/steep.rake +0 -11
- data/tasks/terminal_preview/app_screenshot.rb +0 -45
- data/tasks/terminal_preview/crash_report.rb +0 -54
- data/tasks/terminal_preview/example_app.rb +0 -27
- data/tasks/terminal_preview/launcher_script.rb +0 -48
- data/tasks/terminal_preview/preview_collection.rb +0 -60
- data/tasks/terminal_preview/preview_timing.rb +0 -24
- data/tasks/terminal_preview/safety_confirmation.rb +0 -58
- data/tasks/terminal_preview/saved_screenshot.rb +0 -56
- data/tasks/terminal_preview/system_appearance.rb +0 -13
- data/tasks/terminal_preview/terminal_window.rb +0 -138
- data/tasks/terminal_preview/window_id.rb +0 -16
- data/tasks/terminal_preview.rake +0 -30
- data/tasks/test.rake +0 -36
- data/tasks/website/index_page.rb +0 -30
- data/tasks/website/version.rb +0 -122
- data/tasks/website/version_menu.rb +0 -68
- data/tasks/website/versioned_documentation.rb +0 -83
- data/tasks/website/website.rb +0 -53
- data/tasks/website.rake +0 -28
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: MIT-0
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
9
|
-
require "ratatui_ruby"
|
|
10
|
-
|
|
11
|
-
# Demonstrates branding visualization with the official logo.
|
|
12
|
-
#
|
|
13
|
-
# Branding is important for identity. Users need to recognize the tools they use.
|
|
14
|
-
#
|
|
15
|
-
# This demo showcases the <tt>RatatuiLogo</tt> widget. It renders the logo in a centered layout.
|
|
16
|
-
#
|
|
17
|
-
# Use it to understand how to incorporate the project's visual identity into your terminal application.
|
|
18
|
-
#
|
|
19
|
-
# === Example
|
|
20
|
-
#
|
|
21
|
-
# Run the demo from the terminal:
|
|
22
|
-
#
|
|
23
|
-
# ruby examples/widget_ratatui_logo/app.rb
|
|
24
|
-
#
|
|
25
|
-
# rdoc-image:/doc/images/widget_ratatui_logo.png
|
|
26
|
-
class WidgetRatatuiLogo
|
|
27
|
-
def run
|
|
28
|
-
RatatuiRuby.run do |tui|
|
|
29
|
-
loop do
|
|
30
|
-
render(tui)
|
|
31
|
-
break if handle_input(tui) == :quit
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
private def render(tui)
|
|
37
|
-
tui.draw do |frame|
|
|
38
|
-
# Layout
|
|
39
|
-
layout = tui.layout_split(
|
|
40
|
-
frame.area,
|
|
41
|
-
direction: :vertical,
|
|
42
|
-
constraints: [
|
|
43
|
-
tui.constraint_fill(1), # Fill remaining space
|
|
44
|
-
tui.constraint_length(3),
|
|
45
|
-
]
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
# Main Area
|
|
49
|
-
main_area = layout[0]
|
|
50
|
-
|
|
51
|
-
# Center the logo using nested Layouts
|
|
52
|
-
# Logo is roughly 47x8
|
|
53
|
-
# Vertical Center
|
|
54
|
-
v_center_layout = tui.layout_split(
|
|
55
|
-
main_area,
|
|
56
|
-
direction: :vertical,
|
|
57
|
-
flex: :center,
|
|
58
|
-
constraints: [tui.constraint_length(10)] # Height + margin
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
# Horizontal Center
|
|
62
|
-
h_center_layout = tui.layout_split(
|
|
63
|
-
v_center_layout[0],
|
|
64
|
-
direction: :horizontal,
|
|
65
|
-
flex: :center,
|
|
66
|
-
constraints: [tui.constraint_length(50)] # Width + margin
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
# Main content: The Logo
|
|
70
|
-
logo = RatatuiRuby::Widgets::RatatuiLogo.new
|
|
71
|
-
frame.render_widget(logo, h_center_layout[0])
|
|
72
|
-
|
|
73
|
-
# Control Panel
|
|
74
|
-
control_area = layout[1]
|
|
75
|
-
|
|
76
|
-
control_text = tui.text_line(spans: [
|
|
77
|
-
tui.text_span(content: "q", style: tui.style(modifiers: [:bold, :underlined])),
|
|
78
|
-
tui.text_span(content: ": Quit"),
|
|
79
|
-
])
|
|
80
|
-
|
|
81
|
-
control_panel = tui.paragraph(
|
|
82
|
-
text: [control_text],
|
|
83
|
-
block: tui.block(
|
|
84
|
-
title: "Controls",
|
|
85
|
-
borders: [:top],
|
|
86
|
-
style: tui.style(fg: :dark_gray)
|
|
87
|
-
)
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
frame.render_widget(control_panel, control_area)
|
|
91
|
-
end
|
|
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
|
-
else
|
|
99
|
-
nil
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
WidgetRatatuiLogo.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 Mascot Example
|
|
7
|
-
|
|
8
|
-
[](app.rb)
|
|
9
|
-
|
|
10
|
-
Demonstrates the project mascot widget for adding personality.
|
|
11
|
-
|
|
12
|
-
Interfaces can feel clinical. A friendly mascot adds charm and brand identity to your terminal application.
|
|
13
|
-
|
|
14
|
-
## Features Demonstrated
|
|
15
|
-
|
|
16
|
-
- **RatatuiMascot Widget**: Renders the ASCII art mascot.
|
|
17
|
-
- **Block Integration**: Wrapping the mascot in a bordered block title.
|
|
18
|
-
|
|
19
|
-
## Hotkeys
|
|
20
|
-
|
|
21
|
-
- **b**: Toggle Block Border (`block`)
|
|
22
|
-
- **q**: Quit
|
|
23
|
-
|
|
24
|
-
## Usage
|
|
25
|
-
|
|
26
|
-
<!-- SPDX-SnippetBegin -->
|
|
27
|
-
<!--
|
|
28
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
29
|
-
SPDX-License-Identifier: MIT-0
|
|
30
|
-
-->
|
|
31
|
-
```bash
|
|
32
|
-
ruby examples/widget_ratatui_mascot/app.rb
|
|
33
|
-
```
|
|
34
|
-
<!-- SPDX-SnippetEnd -->
|
|
35
|
-
|
|
36
|
-
## Learning Outcomes
|
|
37
|
-
|
|
38
|
-
Use this example if you need to...
|
|
39
|
-
|
|
40
|
-
- Add visual flair to your UI.
|
|
41
|
-
- Create a friendly empty state or success screen.
|
|
42
|
-
|
|
43
|
-
[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
|
-
# Demonstrates personality and charm with the project mascot.
|
|
12
|
-
#
|
|
13
|
-
# Interfaces without personality feel clinical and dry. Users appreciate a friendly face in their terminal.
|
|
14
|
-
#
|
|
15
|
-
# This demo showcases the <tt>RatatuiMascot</tt> widget. It provides an interactive playground where you can toggle the surrounding block.
|
|
16
|
-
#
|
|
17
|
-
# Use it to understand how to add a playful touch to your terminal dashboards or about screens.
|
|
18
|
-
#
|
|
19
|
-
# === Example
|
|
20
|
-
#
|
|
21
|
-
# Run the demo from the terminal:
|
|
22
|
-
#
|
|
23
|
-
# ruby examples/widget_ratatui_mascot/app.rb
|
|
24
|
-
#
|
|
25
|
-
# rdoc-image:/doc/images/widget_ratatui_mascot.png
|
|
26
|
-
class WidgetRatatuiMascot
|
|
27
|
-
def initialize
|
|
28
|
-
@show_block = true
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def run
|
|
32
|
-
RatatuiRuby.run do |tui|
|
|
33
|
-
loop do
|
|
34
|
-
tui.draw do |frame|
|
|
35
|
-
# Layout: Top (Mascot), Bottom (Controls)
|
|
36
|
-
layout = tui.layout_split(
|
|
37
|
-
frame.area,
|
|
38
|
-
direction: :vertical,
|
|
39
|
-
constraints: [
|
|
40
|
-
tui.constraint_fill(1),
|
|
41
|
-
tui.constraint_length(4),
|
|
42
|
-
]
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
mascot_area = layout[0]
|
|
46
|
-
controls_area = layout[1]
|
|
47
|
-
|
|
48
|
-
# Mascot Widget
|
|
49
|
-
block = if @show_block
|
|
50
|
-
tui.block(
|
|
51
|
-
title: "Ratatui Mascot",
|
|
52
|
-
borders: [:all],
|
|
53
|
-
border_type: :rounded,
|
|
54
|
-
border_style: { fg: :green }
|
|
55
|
-
)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
mascot = tui.ratatui_mascot(block:)
|
|
59
|
-
frame.render_widget(mascot, mascot_area)
|
|
60
|
-
|
|
61
|
-
# Controls
|
|
62
|
-
controls_text = [
|
|
63
|
-
tui.text_span(content: "q", style: tui.style(modifiers: [:bold, :underlined])),
|
|
64
|
-
tui.text_span(content: " Quit"),
|
|
65
|
-
tui.text_span(content: " "),
|
|
66
|
-
tui.text_span(content: "b", style: tui.style(modifiers: [:bold, :underlined])),
|
|
67
|
-
tui.text_span(content: " Toggle Block #{@show_block ? '(On)' : '(Off)'}"),
|
|
68
|
-
]
|
|
69
|
-
|
|
70
|
-
controls_paragraph = tui.paragraph(
|
|
71
|
-
text: tui.text_line(spans: controls_text),
|
|
72
|
-
block: tui.block(borders: [:top], title: "Controls")
|
|
73
|
-
)
|
|
74
|
-
frame.render_widget(controls_paragraph, controls_area)
|
|
75
|
-
end
|
|
76
|
-
break if handle_input(tui) == :quit
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
private def handle_input(tui)
|
|
82
|
-
event = tui.poll_event
|
|
83
|
-
|
|
84
|
-
if event.key?
|
|
85
|
-
case event.char
|
|
86
|
-
when "q" then :quit
|
|
87
|
-
when "b" then @show_block = !@show_block
|
|
88
|
-
end
|
|
89
|
-
elsif event.ctrl_c?
|
|
90
|
-
:quit
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
WidgetRatatuiMascot.new.run if __FILE__ == $PROGRAM_NAME
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
-
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
-
-->
|
|
5
|
-
|
|
6
|
-
# Rect (Area, Rectangle) Example
|
|
7
|
-
|
|
8
|
-
[](app.rb)
|
|
9
|
-
|
|
10
|
-
Demonstrates the Rect geometry primitive and hit-testing patterns.
|
|
11
|
-
|
|
12
|
-
TUI layouts are composed of rectangles. Understanding how to manipulate `Rect` objects, reuse them from the layout phase, and use them for mouse interaction is critical for building interactive apps.
|
|
13
|
-
|
|
14
|
-
## Features Demonstrated
|
|
15
|
-
|
|
16
|
-
- **Rect Attributes**: Investigating x, y, width, and height.
|
|
17
|
-
- **Edge Accessors**: Using `left`, `right`, `top`, `bottom` instead of manual math.
|
|
18
|
-
- **Size Methods**: Checking `area` and `empty?` for guard clauses.
|
|
19
|
-
- **Geometry Transformations**: Computing `inner`, `offset`, `union`, and `clamp`.
|
|
20
|
-
- **Iterators**: Traversing `rows`, `columns`, and `positions`.
|
|
21
|
-
- **Cached Layout Pattern**: Computing constraints in the render loop and reusing the resulting `Rect`s in the event loop for logic.
|
|
22
|
-
- **Hit Testing**: Using `Rect#contains?(x, y)` to determine if a mouse click happened inside a specific panel.
|
|
23
|
-
|
|
24
|
-
## Hotkeys
|
|
25
|
-
|
|
26
|
-
- **Arrows (←/→)**: Expand/Shrink Sidebar Width (Layout Constraint)
|
|
27
|
-
- **Arrows (↑/↓)**: Navigate Menu Selection (`selected_index`)
|
|
28
|
-
- **Mouse Click**: Click anywhere to see which Rect detects the hit (`contains?`)
|
|
29
|
-
- **q**: Quit
|
|
30
|
-
|
|
31
|
-
## Usage
|
|
32
|
-
|
|
33
|
-
<!-- SPDX-SnippetBegin -->
|
|
34
|
-
<!--
|
|
35
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
36
|
-
SPDX-License-Identifier: MIT-0
|
|
37
|
-
-->
|
|
38
|
-
```bash
|
|
39
|
-
ruby examples/widget_rect/app.rb
|
|
40
|
-
```
|
|
41
|
-
<!-- SPDX-SnippetEnd -->
|
|
42
|
-
|
|
43
|
-
## Learning Outcomes
|
|
44
|
-
|
|
45
|
-
Use this example if you need to...
|
|
46
|
-
|
|
47
|
-
- Handle mouse clicks on specific buttons or areas.
|
|
48
|
-
- Create resizable panes (like a split pane in an IDE).
|
|
49
|
-
- Debug layout issues by inspecting Rect coordinates.
|
|
50
|
-
- Compute inner padding, bounding boxes, or clamped popups.
|
|
51
|
-
- Iterate over rows, columns, or individual positions within a region.
|
|
52
|
-
|
|
53
|
-
[Read the source code →](app.rb)
|
data/examples/widget_rect/app.rb
DELETED
|
@@ -1,222 +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
|
-
# Rect Widget Showcase
|
|
12
|
-
#
|
|
13
|
-
# Demonstrates the Rect class and the Cached Layout Pattern.
|
|
14
|
-
#
|
|
15
|
-
# Rect is the fundamental geometry primitive for TUI layout. This example shows:
|
|
16
|
-
# - Rect attributes: x, y, width, height
|
|
17
|
-
# - Edge accessors: left, right, top, bottom
|
|
18
|
-
# - Geometry methods: area, empty?, union, inner, offset, clamp
|
|
19
|
-
# - Iterators: rows, columns, positions
|
|
20
|
-
# - Rect#contains? for hit testing mouse clicks
|
|
21
|
-
# - Layout.split returning cached rects for reuse
|
|
22
|
-
#
|
|
23
|
-
# Controls:
|
|
24
|
-
# ←/→: Adjust sidebar width
|
|
25
|
-
# ↑/↓: Navigate menu items
|
|
26
|
-
# Mouse: Click panels to test Rect#contains?
|
|
27
|
-
# q: Quit
|
|
28
|
-
class WidgetRect
|
|
29
|
-
MENU_ITEMS = ["Dashboard", "Analytics", "Settings", "Logs", "Help"].freeze
|
|
30
|
-
|
|
31
|
-
def initialize
|
|
32
|
-
@sidebar_width = 20
|
|
33
|
-
@selected_index = 0
|
|
34
|
-
@last_action = "Click any panel to test Rect#contains?"
|
|
35
|
-
@click_count = 0
|
|
36
|
-
@sidebar_rect = nil
|
|
37
|
-
@main_rect = nil
|
|
38
|
-
@controls_rect = nil
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def run
|
|
42
|
-
RatatuiRuby.run do |tui|
|
|
43
|
-
@tui = tui
|
|
44
|
-
@hotkey_style = @tui.style(modifiers: [:bold, :underlined])
|
|
45
|
-
@label_style = @tui.style(modifiers: [:bold])
|
|
46
|
-
@dim_style = @tui.style(fg: :dark_gray)
|
|
47
|
-
|
|
48
|
-
loop do
|
|
49
|
-
render
|
|
50
|
-
break if handle_input == :quit
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
private def render
|
|
56
|
-
@tui.draw do |frame|
|
|
57
|
-
@main_rect, @controls_rect = @tui.layout_split(
|
|
58
|
-
frame.area,
|
|
59
|
-
direction: :vertical,
|
|
60
|
-
constraints: [
|
|
61
|
-
@tui.constraint_fill(1),
|
|
62
|
-
@tui.constraint_length(5),
|
|
63
|
-
]
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
@sidebar_rect, @content_rect = @tui.layout_split(
|
|
67
|
-
@main_rect,
|
|
68
|
-
direction: :horizontal,
|
|
69
|
-
constraints: [
|
|
70
|
-
@tui.constraint_length(@sidebar_width),
|
|
71
|
-
@tui.constraint_fill(1),
|
|
72
|
-
]
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
render_sidebar(frame)
|
|
76
|
-
render_content(frame)
|
|
77
|
-
render_controls(frame)
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
private def render_sidebar(frame)
|
|
82
|
-
sidebar = @tui.list(
|
|
83
|
-
items: MENU_ITEMS,
|
|
84
|
-
selected_index: @selected_index,
|
|
85
|
-
highlight_style: @tui.style(fg: :black, bg: :white, modifiers: [:bold]),
|
|
86
|
-
highlight_symbol: "> ",
|
|
87
|
-
block: @tui.block(title: "Menu", borders: [:all])
|
|
88
|
-
)
|
|
89
|
-
frame.render_widget(sidebar, @sidebar_rect)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
private def render_content(frame)
|
|
93
|
-
r = @content_rect
|
|
94
|
-
inner_r = r.inner(2)
|
|
95
|
-
offset_r = r.offset(3, 2)
|
|
96
|
-
bounds = RatatuiRuby::Layout::Rect.new(x: 0, y: 0, width: 50, height: 20)
|
|
97
|
-
clamped = r.clamp(bounds)
|
|
98
|
-
union_r = r.union(@sidebar_rect)
|
|
99
|
-
|
|
100
|
-
# Extract position and size from rect
|
|
101
|
-
pos = r.position # => Position(x:, y:)
|
|
102
|
-
size = r.size # => Size(width:, height:)
|
|
103
|
-
|
|
104
|
-
text_content = [
|
|
105
|
-
@tui.text_line(spans: [
|
|
106
|
-
@tui.text_span(content: "Active View: ", style: @label_style),
|
|
107
|
-
@tui.text_span(content: MENU_ITEMS[@selected_index], style: @tui.style(fg: :green)),
|
|
108
|
-
]),
|
|
109
|
-
@tui.text_line(spans: [
|
|
110
|
-
@tui.text_span(content: "Rect Attributes ", style: @label_style),
|
|
111
|
-
@tui.text_span(content: "(from Layout.split):", style: @dim_style),
|
|
112
|
-
]),
|
|
113
|
-
" x:#{r.x} y:#{r.y} width:#{r.width} height:#{r.height}",
|
|
114
|
-
@tui.text_line(spans: [
|
|
115
|
-
@tui.text_span(content: "Edge Accessors:", style: @label_style),
|
|
116
|
-
]),
|
|
117
|
-
" left:#{r.left} right:#{r.right} top:#{r.top} bottom:#{r.bottom}",
|
|
118
|
-
@tui.text_line(spans: [
|
|
119
|
-
@tui.text_span(content: "Conversion Methods ", style: @label_style),
|
|
120
|
-
@tui.text_span(content: "(as_position/as_size):", style: @dim_style),
|
|
121
|
-
]),
|
|
122
|
-
" Position: x=#{pos.x} y=#{pos.y} Size: #{size.width}x#{size.height}",
|
|
123
|
-
@tui.text_line(spans: [
|
|
124
|
-
@tui.text_span(content: "Geometry Transformations:", style: @label_style),
|
|
125
|
-
]),
|
|
126
|
-
" inner(2): x:#{inner_r.x} y:#{inner_r.y} w:#{inner_r.width} h:#{inner_r.height}",
|
|
127
|
-
" offset(3,2): x:#{offset_r.x} y:#{offset_r.y} clamp: x:#{clamped.x} y:#{clamped.y}",
|
|
128
|
-
" union(sidebar): w:#{union_r.width} h:#{union_r.height}",
|
|
129
|
-
@tui.text_line(spans: [
|
|
130
|
-
@tui.text_span(content: "Hit Testing ", style: @label_style),
|
|
131
|
-
@tui.text_span(content: "(Rect#contains?):", style: @dim_style),
|
|
132
|
-
]),
|
|
133
|
-
" Clicks: #{@click_count} | #{@last_action}",
|
|
134
|
-
]
|
|
135
|
-
|
|
136
|
-
paragraph = @tui.paragraph(
|
|
137
|
-
text: text_content,
|
|
138
|
-
block: @tui.block(title: "Content", borders: [:all])
|
|
139
|
-
)
|
|
140
|
-
frame.render_widget(paragraph, @content_rect)
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
private def render_controls(frame)
|
|
144
|
-
controls = @tui.block(
|
|
145
|
-
title: "Controls",
|
|
146
|
-
borders: [:all],
|
|
147
|
-
children: [
|
|
148
|
-
@tui.paragraph(
|
|
149
|
-
text: [
|
|
150
|
-
@tui.text_line(spans: [
|
|
151
|
-
@tui.text_span(content: "←", style: @hotkey_style),
|
|
152
|
-
@tui.text_span(content: "/"),
|
|
153
|
-
@tui.text_span(content: "→", style: @hotkey_style),
|
|
154
|
-
@tui.text_span(content: ": Sidebar width "),
|
|
155
|
-
@tui.text_span(content: "↑", style: @hotkey_style),
|
|
156
|
-
@tui.text_span(content: "/"),
|
|
157
|
-
@tui.text_span(content: "↓", style: @hotkey_style),
|
|
158
|
-
@tui.text_span(content: ": Menu selection "),
|
|
159
|
-
@tui.text_span(content: "Click", style: @hotkey_style),
|
|
160
|
-
@tui.text_span(content: ": Hit test "),
|
|
161
|
-
@tui.text_span(content: "q", style: @hotkey_style),
|
|
162
|
-
@tui.text_span(content: ": Quit"),
|
|
163
|
-
]),
|
|
164
|
-
]
|
|
165
|
-
),
|
|
166
|
-
]
|
|
167
|
-
)
|
|
168
|
-
frame.render_widget(controls, @controls_rect)
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
private def handle_input
|
|
172
|
-
case @tui.poll_event
|
|
173
|
-
in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
|
|
174
|
-
:quit
|
|
175
|
-
in type: :key, code: "left"
|
|
176
|
-
@sidebar_width = [@sidebar_width - 2, 10].max
|
|
177
|
-
@last_action = "Layout changed: sidebar_width=#{@sidebar_width}"
|
|
178
|
-
nil
|
|
179
|
-
in type: :key, code: "right"
|
|
180
|
-
@sidebar_width = [@sidebar_width + 2, 40].min
|
|
181
|
-
@last_action = "Layout changed: sidebar_width=#{@sidebar_width}"
|
|
182
|
-
nil
|
|
183
|
-
in type: :key, code: "up"
|
|
184
|
-
@selected_index = (@selected_index - 1) % MENU_ITEMS.size
|
|
185
|
-
@last_action = "Selected: #{MENU_ITEMS[@selected_index]}"
|
|
186
|
-
nil
|
|
187
|
-
in type: :key, code: "down"
|
|
188
|
-
@selected_index = (@selected_index + 1) % MENU_ITEMS.size
|
|
189
|
-
@last_action = "Selected: #{MENU_ITEMS[@selected_index]}"
|
|
190
|
-
nil
|
|
191
|
-
in type: :mouse, kind: "down", x: click_x, y: click_y
|
|
192
|
-
handle_click(click_x, click_y)
|
|
193
|
-
nil
|
|
194
|
-
else
|
|
195
|
-
nil
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
private def handle_click(x, y)
|
|
200
|
-
@click_count += 1
|
|
201
|
-
|
|
202
|
-
if @sidebar_rect&.contains?(x, y)
|
|
203
|
-
relative_y = y - @sidebar_rect.y - 1
|
|
204
|
-
if relative_y >= 0 && relative_y < MENU_ITEMS.size
|
|
205
|
-
old_item = MENU_ITEMS[@selected_index]
|
|
206
|
-
@selected_index = relative_y
|
|
207
|
-
new_item = MENU_ITEMS[@selected_index]
|
|
208
|
-
@last_action = "sidebar.contains?(#{x},#{y})=true → #{old_item}→#{new_item}"
|
|
209
|
-
else
|
|
210
|
-
@last_action = "sidebar.contains?(#{x},#{y})=true (empty area)"
|
|
211
|
-
end
|
|
212
|
-
elsif @content_rect&.contains?(x, y)
|
|
213
|
-
@last_action = "content.contains?(#{x},#{y})=true"
|
|
214
|
-
elsif @controls_rect&.contains?(x, y)
|
|
215
|
-
@last_action = "controls.contains?(#{x},#{y})=true"
|
|
216
|
-
else
|
|
217
|
-
@last_action = "No rect contains (#{x},#{y})"
|
|
218
|
-
end
|
|
219
|
-
end
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
WidgetRect.new.run if __FILE__ == $0
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
-
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
-
-->
|
|
5
|
-
|
|
6
|
-
# Render (Custom Widget) Example
|
|
7
|
-
|
|
8
|
-
[](app.rb)
|
|
9
|
-
|
|
10
|
-
Demonstrates how to build Custom Widgets using absolute coordinates.
|
|
11
|
-
|
|
12
|
-
Sometimes standard widgets aren't enough. You need to draw custom shapes, games, or graphs. This example shows how to implement the `render(area)` contract to draw anything you want while respecting layout boundaries.
|
|
13
|
-
|
|
14
|
-
## Features Demonstrated
|
|
15
|
-
|
|
16
|
-
- **Custom Widget Contract**: Implementing a class with `render(area)`.
|
|
17
|
-
- **Coordinate Offsets**: Creating drawing logic that works regardless of where the widget is placed on screen (using `area.x + offset`).
|
|
18
|
-
- **Composability**: Wrapping custom widgets in standard `Block`s with borders.
|
|
19
|
-
|
|
20
|
-
## Hotkeys
|
|
21
|
-
|
|
22
|
-
- **n**: Next Widget (Diagonal -> Checkerboard -> Border)
|
|
23
|
-
- **p**: Previous Widget
|
|
24
|
-
- **q**: Quit
|
|
25
|
-
|
|
26
|
-
## Usage
|
|
27
|
-
|
|
28
|
-
<!-- SPDX-SnippetBegin -->
|
|
29
|
-
<!--
|
|
30
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
31
|
-
SPDX-License-Identifier: MIT-0
|
|
32
|
-
-->
|
|
33
|
-
```bash
|
|
34
|
-
ruby examples/widget_render/app.rb
|
|
35
|
-
```
|
|
36
|
-
<!-- SPDX-SnippetEnd -->
|
|
37
|
-
|
|
38
|
-
## Learning Outcomes
|
|
39
|
-
|
|
40
|
-
Use this example if you need to...
|
|
41
|
-
|
|
42
|
-
- Build a game (Snake, Tetris) inside the terminal.
|
|
43
|
-
- Create a specialized visualization (Network topology graph).
|
|
44
|
-
- Draw custom UI elements not provided by the library.
|
|
45
|
-
|
|
46
|
-
[Read the source code →](app.rb)
|