ratatui_ruby 0.5.0 → 0.6.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 +1 -1
- data/.builds/ruby-3.3.yml +1 -1
- data/.builds/ruby-3.4.yml +1 -1
- data/.builds/ruby-4.0.0.yml +1 -1
- data/AGENTS.md +6 -0
- data/CHANGELOG.md +44 -7
- data/README.md +11 -4
- data/REUSE.toml +2 -7
- data/doc/application_architecture.md +84 -10
- data/doc/application_testing.md +75 -29
- data/doc/contributors/design/ruby_frontend.md +39 -3
- data/doc/contributors/design/rust_backend.md +1 -0
- data/doc/contributors/developing_examples.md +129 -44
- data/doc/contributors/examples_audit/p1_high.md +21 -0
- data/doc/contributors/examples_audit/p2_moderate.md +81 -0
- data/doc/contributors/examples_audit.md +41 -0
- data/doc/event_handling.md +11 -3
- data/doc/images/app_all_events.png +0 -0
- data/doc/images/app_color_picker.png +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_demo.png +0 -0
- data/doc/images/widget_block_demo.png +0 -0
- data/doc/images/widget_canvas_demo.png +0 -0
- data/doc/images/widget_cell_demo.png +0 -0
- data/doc/images/widget_center_demo.png +0 -0
- data/doc/images/widget_chart_demo.png +0 -0
- data/doc/images/widget_list_demo.png +0 -0
- data/doc/images/widget_overlay_demo.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_sparkline_demo.png +0 -0
- data/doc/images/widget_table_demo.png +0 -0
- data/doc/images/widget_tabs_demo.png +0 -0
- data/doc/images/widget_text_width.png +0 -0
- data/doc/quickstart.md +69 -76
- data/doc/terminal_limitations.md +92 -0
- data/examples/app_all_events/README.md +45 -27
- data/examples/app_all_events/app.rb +38 -35
- data/examples/app_all_events/model/app_model.rb +157 -0
- data/examples/app_all_events/model/event_entry.rb +17 -0
- data/examples/app_all_events/model/msg.rb +37 -0
- data/examples/app_all_events/update.rb +73 -0
- data/examples/app_all_events/view/app_view.rb +8 -8
- data/examples/app_all_events/view/controls_view.rb +8 -6
- data/examples/app_all_events/view/counts_view.rb +12 -8
- data/examples/app_all_events/view/live_view.rb +8 -7
- data/examples/app_all_events/view/log_view.rb +10 -15
- data/examples/app_color_picker/README.md +84 -44
- data/examples/app_color_picker/app.rb +24 -62
- data/examples/app_color_picker/controls.rb +90 -0
- data/examples/app_color_picker/copy_dialog.rb +45 -49
- data/examples/app_color_picker/export_pane.rb +126 -0
- data/examples/app_color_picker/input.rb +99 -67
- data/examples/app_color_picker/main_container.rb +178 -0
- data/examples/app_color_picker/palette.rb +55 -26
- data/examples/app_login_form/README.md +47 -0
- data/examples/app_login_form/app.rb +2 -3
- data/examples/app_stateful_interaction/README.md +31 -0
- data/examples/app_stateful_interaction/app.rb +272 -0
- data/examples/timeout_demo.rb +43 -0
- data/examples/verify_quickstart_dsl/README.md +48 -0
- data/examples/verify_quickstart_dsl/app.rb +2 -0
- data/examples/verify_quickstart_layout/README.md +71 -0
- data/examples/verify_quickstart_layout/app.rb +2 -0
- data/examples/verify_quickstart_lifecycle/README.md +56 -0
- data/examples/verify_quickstart_lifecycle/app.rb +8 -2
- data/examples/verify_readme_usage/README.md +43 -0
- data/examples/verify_readme_usage/app.rb +8 -2
- data/examples/widget_barchart_demo/README.md +49 -0
- data/examples/widget_barchart_demo/app.rb +5 -5
- data/examples/widget_block_demo/README.md +34 -0
- data/examples/widget_block_demo/app.rb +256 -0
- data/examples/widget_box_demo/README.md +45 -0
- data/examples/widget_calendar_demo/README.md +39 -0
- data/examples/widget_canvas_demo/README.md +27 -0
- data/examples/widget_canvas_demo/app.rb +123 -0
- data/examples/widget_cell_demo/README.md +36 -0
- data/examples/widget_cell_demo/app.rb +31 -24
- data/examples/widget_center_demo/README.md +29 -0
- data/examples/widget_center_demo/app.rb +116 -0
- data/examples/widget_chart_demo/README.md +41 -0
- data/examples/widget_chart_demo/app.rb +7 -2
- data/examples/widget_gauge_demo/README.md +41 -0
- data/examples/widget_layout_split/README.md +44 -0
- data/examples/widget_line_gauge_demo/README.md +41 -0
- data/examples/widget_list_demo/README.md +49 -0
- data/examples/widget_list_demo/app.rb +91 -107
- data/examples/widget_map_demo/README.md +39 -0
- data/examples/{app_map_demo → widget_map_demo}/app.rb +2 -2
- data/examples/widget_overlay_demo/app.rb +248 -0
- data/examples/widget_popup_demo/README.md +36 -0
- data/examples/widget_ratatui_logo_demo/README.md +34 -0
- data/examples/widget_ratatui_mascot_demo/README.md +34 -0
- data/examples/widget_rect/README.md +38 -0
- data/examples/widget_render/README.md +37 -0
- data/examples/widget_rich_text/README.md +35 -0
- data/examples/widget_rich_text/app.rb +62 -33
- data/examples/widget_scroll_text/README.md +37 -0
- data/examples/widget_scroll_text/app.rb +0 -1
- data/examples/widget_scrollbar_demo/README.md +37 -0
- data/examples/widget_sparkline_demo/README.md +42 -0
- data/examples/widget_sparkline_demo/app.rb +4 -3
- data/examples/widget_style_colors/README.md +34 -0
- data/examples/widget_table_demo/README.md +48 -0
- data/examples/{app_table_select → widget_table_demo}/app.rb +46 -8
- data/examples/widget_tabs_demo/README.md +41 -0
- data/examples/widget_tabs_demo/app.rb +15 -1
- data/examples/widget_text_width/README.md +35 -0
- data/examples/widget_text_width/app.rb +106 -0
- data/exe/.gitkeep +0 -0
- data/ext/ratatui_ruby/Cargo.lock +11 -4
- data/ext/ratatui_ruby/Cargo.toml +2 -1
- data/ext/ratatui_ruby/src/events.rs +238 -26
- data/ext/ratatui_ruby/src/frame.rs +113 -1
- data/ext/ratatui_ruby/src/lib.rs +34 -4
- data/ext/ratatui_ruby/src/string_width.rs +101 -0
- data/ext/ratatui_ruby/src/terminal.rs +39 -15
- data/ext/ratatui_ruby/src/text.rs +1 -1
- data/ext/ratatui_ruby/src/widgets/barchart.rs +24 -6
- data/ext/ratatui_ruby/src/widgets/gauge.rs +9 -2
- data/ext/ratatui_ruby/src/widgets/line_gauge.rs +9 -2
- data/ext/ratatui_ruby/src/widgets/list.rs +179 -3
- data/ext/ratatui_ruby/src/widgets/list_state.rs +137 -0
- data/ext/ratatui_ruby/src/widgets/mod.rs +3 -0
- data/ext/ratatui_ruby/src/widgets/scrollbar.rs +93 -1
- data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
- data/ext/ratatui_ruby/src/widgets/table.rs +113 -1
- data/ext/ratatui_ruby/src/widgets/table_state.rs +121 -0
- data/lib/ratatui_ruby/cell.rb +4 -4
- data/lib/ratatui_ruby/event/key/character.rb +35 -0
- data/lib/ratatui_ruby/event/key/media.rb +44 -0
- data/lib/ratatui_ruby/event/key/modifier.rb +95 -0
- data/lib/ratatui_ruby/event/key/navigation.rb +55 -0
- data/lib/ratatui_ruby/event/key/system.rb +45 -0
- data/lib/ratatui_ruby/event/key.rb +111 -51
- data/lib/ratatui_ruby/event/mouse.rb +3 -3
- data/lib/ratatui_ruby/event/paste.rb +1 -1
- data/lib/ratatui_ruby/frame.rb +96 -0
- data/lib/ratatui_ruby/list_state.rb +88 -0
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +2 -2
- data/lib/ratatui_ruby/schema/cursor.rb +5 -0
- data/lib/ratatui_ruby/schema/gauge.rb +3 -1
- data/lib/ratatui_ruby/schema/line_gauge.rb +2 -2
- data/lib/ratatui_ruby/schema/list.rb +25 -4
- data/lib/ratatui_ruby/schema/list_item.rb +41 -0
- data/lib/ratatui_ruby/schema/rect.rb +43 -0
- data/lib/ratatui_ruby/schema/style.rb +24 -4
- data/lib/ratatui_ruby/schema/table.rb +21 -3
- data/lib/ratatui_ruby/schema/text.rb +69 -1
- data/lib/ratatui_ruby/scrollbar_state.rb +112 -0
- data/lib/ratatui_ruby/session/autodoc.rb +65 -0
- data/lib/ratatui_ruby/session.rb +22 -7
- data/lib/ratatui_ruby/table_state.rb +90 -0
- data/lib/ratatui_ruby/test_helper/event_injection.rb +169 -0
- data/lib/ratatui_ruby/test_helper/snapshot.rb +390 -0
- data/lib/ratatui_ruby/test_helper/style_assertions.rb +351 -0
- data/lib/ratatui_ruby/test_helper/terminal.rb +127 -0
- data/lib/ratatui_ruby/test_helper/test_doubles.rb +68 -0
- data/lib/ratatui_ruby/test_helper.rb +65 -358
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby.rb +42 -19
- data/sig/examples/app_stateful_interaction/app.rbs +33 -0
- data/sig/examples/widget_block_demo/app.rbs +32 -0
- data/sig/examples/{app_map_demo → widget_map_demo}/app.rbs +2 -2
- data/sig/examples/{app_table_select → widget_table_demo}/app.rbs +2 -2
- data/sig/examples/{widget_table_flex → widget_text_width}/app.rbs +2 -3
- data/sig/ratatui_ruby/event.rbs +11 -1
- data/sig/ratatui_ruby/frame.rbs +2 -0
- data/sig/ratatui_ruby/list_state.rbs +13 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +2 -2
- data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +3 -3
- data/sig/ratatui_ruby/schema/gauge.rbs +2 -2
- data/sig/ratatui_ruby/schema/line_gauge.rbs +2 -2
- data/sig/ratatui_ruby/schema/list.rbs +4 -2
- data/sig/ratatui_ruby/schema/list_item.rbs +10 -0
- data/sig/ratatui_ruby/schema/rect.rbs +3 -0
- data/sig/ratatui_ruby/schema/style.rbs +3 -3
- data/sig/ratatui_ruby/schema/table.rbs +3 -1
- data/sig/ratatui_ruby/schema/text.rbs +8 -6
- data/sig/ratatui_ruby/scrollbar_state.rbs +18 -0
- data/sig/ratatui_ruby/session.rbs +13 -0
- data/sig/ratatui_ruby/table_state.rbs +15 -0
- data/sig/ratatui_ruby/test_helper/event_injection.rbs +16 -0
- data/sig/ratatui_ruby/test_helper/snapshot.rbs +12 -0
- data/sig/ratatui_ruby/test_helper/style_assertions.rbs +64 -0
- data/sig/ratatui_ruby/test_helper/terminal.rbs +14 -0
- data/sig/ratatui_ruby/test_helper/test_doubles.rbs +22 -0
- data/sig/ratatui_ruby/test_helper.rbs +5 -4
- data/tasks/autodoc/examples.rb +79 -0
- data/tasks/autodoc/inventory.rb +9 -7
- data/tasks/autodoc.rake +11 -5
- data/tasks/bump/changelog.rb +3 -3
- data/tasks/bump/links.rb +67 -0
- data/tasks/sourcehut.rake +61 -21
- data/tasks/terminal_preview/app_screenshot.rb +13 -3
- data/tasks/terminal_preview/saved_screenshot.rb +4 -3
- metadata +111 -37
- data/doc/images/app_table_select.png +0 -0
- data/doc/images/widget_block_padding.png +0 -0
- data/doc/images/widget_block_titles.png +0 -0
- data/doc/images/widget_list_styles.png +0 -0
- data/examples/app_all_events/model/events.rb +0 -180
- data/examples/app_all_events/model/highlight.rb +0 -57
- data/examples/app_all_events/test/snapshots/after_focus_lost.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_focus_regained.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_horizontal_resize.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_key_a.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_key_ctrl_x.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_mouse_click.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_mouse_drag.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_multiple_events.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_paste.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_resize.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_right_click.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_vertical_resize.txt +0 -24
- data/examples/app_all_events/test/snapshots/initial_state.txt +0 -24
- data/examples/app_all_events/view_state.rb +0 -42
- data/examples/app_color_picker/scene.rb +0 -201
- data/examples/widget_block_padding/app.rb +0 -67
- data/examples/widget_block_titles/app.rb +0 -69
- data/examples/widget_list_styles/app.rb +0 -141
- data/examples/widget_table_flex/app.rb +0 -95
- data/sig/examples/widget_block_padding/app.rbs +0 -11
- data/sig/examples/widget_block_titles/app.rbs +0 -11
- data/sig/examples/widget_list_styles/app.rbs +0 -11
- data/tasks/bump/comparison_links.rb +0 -41
- /data/doc/images/{app_map_demo.png → widget_map_demo.png} +0 -0
|
@@ -0,0 +1,272 @@
|
|
|
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
|
+
require "faker"
|
|
9
|
+
|
|
10
|
+
# A "Master Class" example demonstrating Stateful Widget Rendering and Interaction.
|
|
11
|
+
#
|
|
12
|
+
# This example shows how to:
|
|
13
|
+
# 1. Use mutable State objects (ListState, TableState) for selection and scrolling
|
|
14
|
+
# 2. Read back the calculated scroll offset from the backend (state.offset)
|
|
15
|
+
# 3. Implement precise mouse-click-to-row interaction using that offset
|
|
16
|
+
class AppStatefulInteraction
|
|
17
|
+
def initialize
|
|
18
|
+
# Data Models
|
|
19
|
+
# Tables are the categories on the left
|
|
20
|
+
@tables = ["Users", "Orders", "Products", "Invoices", "Audit Logs"]
|
|
21
|
+
@headers = {
|
|
22
|
+
"Users" => ["Name", "Email", "Role"],
|
|
23
|
+
"Orders" => ["Order ID", "Status", "Amount"],
|
|
24
|
+
"Products" => ["Product", "SKU", "Status"],
|
|
25
|
+
"Invoices" => ["Invoice #", "Status", "Amount"],
|
|
26
|
+
"Audit Logs" => ["Event", "Action", "IP Address"],
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# Generate dummy data for each table
|
|
30
|
+
# Use fixed seed for deterministic behavior in CI/Tests
|
|
31
|
+
if ENV["CI"] == "true" || ENV["RATA_SEED"]
|
|
32
|
+
seed = (ENV["RATA_SEED"] || 12345).to_i
|
|
33
|
+
Faker::Config.random = Random.new(seed)
|
|
34
|
+
# Also seed Kernel.rand/Array#sample just in case
|
|
35
|
+
srand(seed)
|
|
36
|
+
end
|
|
37
|
+
rand_price = -> { "$#{Faker::Commerce.price(range: 10..500.0)}" }
|
|
38
|
+
|
|
39
|
+
@data = {
|
|
40
|
+
"Users" => Array.new(50) { [Faker::Name.name, Faker::Internet.email, %w[Admin Editor Viewer].sample] },
|
|
41
|
+
"Orders" => Array.new(50) { [Faker::Commerce.promotion_code(digits: 4), ["Completed", "Pending", "Failed"].sample, rand_price.call] },
|
|
42
|
+
"Products" => Array.new(50) { [Faker::Commerce.product_name, "SKU-#{Faker::Number.number(digits: 4)}", ["In Stock", "Low Stock"].sample] },
|
|
43
|
+
"Invoices" => Array.new(50) { ["INV-#{Faker::Number.number(digits: 6)}", ["Paid", "Unpaid"].sample, rand_price.call] },
|
|
44
|
+
"Audit Logs" => Array.new(50) { ["Log #{Faker::Number.unique.number(digits: 3)}", ["Login Success", "Login Failed", "Logout"].sample, Faker::Internet.ip_v4_address] },
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# State Objects - These are mutable and persist across frames!
|
|
48
|
+
@list_state = RatatuiRuby::ListState.new(nil)
|
|
49
|
+
@table_state = RatatuiRuby::TableState.new(nil)
|
|
50
|
+
|
|
51
|
+
# Initialize selection
|
|
52
|
+
@list_state.select(0)
|
|
53
|
+
@table_state.select(0)
|
|
54
|
+
|
|
55
|
+
# Active Pane Focus (:list or :table)
|
|
56
|
+
@active_pane = :list
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def run
|
|
60
|
+
RatatuiRuby.run do |tui|
|
|
61
|
+
@tui = tui
|
|
62
|
+
|
|
63
|
+
# Styles can only be created once TUI is initialized
|
|
64
|
+
@style_active = @tui.style(fg: :yellow, modifiers: [:bold])
|
|
65
|
+
@style_inactive = @tui.style(fg: :dark_gray)
|
|
66
|
+
@style_highlight = @tui.style(bg: :blue, fg: :white, modifiers: [:bold])
|
|
67
|
+
|
|
68
|
+
loop do
|
|
69
|
+
render
|
|
70
|
+
break if handle_input == :quit
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private def render
|
|
76
|
+
@tui.draw do |frame|
|
|
77
|
+
# 1. Layout
|
|
78
|
+
main_area, help_area = @tui.layout_split(
|
|
79
|
+
frame.area,
|
|
80
|
+
direction: :vertical,
|
|
81
|
+
constraints: [
|
|
82
|
+
@tui.constraint_fill(1),
|
|
83
|
+
@tui.constraint_length(1),
|
|
84
|
+
]
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
list_area, table_area = @tui.layout_split(
|
|
88
|
+
main_area,
|
|
89
|
+
direction: :horizontal,
|
|
90
|
+
constraints: [
|
|
91
|
+
@tui.constraint_percentage(30),
|
|
92
|
+
@tui.constraint_percentage(70),
|
|
93
|
+
]
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Save areas for hit testing
|
|
97
|
+
@list_area = list_area
|
|
98
|
+
@table_area = table_area
|
|
99
|
+
|
|
100
|
+
# 2. Render List (Left Pane)
|
|
101
|
+
render_list(frame, list_area)
|
|
102
|
+
|
|
103
|
+
# 3. Render Table (Right Pane)
|
|
104
|
+
render_table(frame, table_area)
|
|
105
|
+
|
|
106
|
+
# 4. Render Help
|
|
107
|
+
help_text = "q: Quit | Tab/Arrows: Nav | Mouse: Click rows (Try it!)"
|
|
108
|
+
frame.render_widget(@tui.paragraph(text: help_text), help_area)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
private def render_list(frame, area)
|
|
113
|
+
is_active = @active_pane == :list
|
|
114
|
+
|
|
115
|
+
# Render main list
|
|
116
|
+
list = @tui.list(
|
|
117
|
+
items: @tables,
|
|
118
|
+
block: @tui.block(
|
|
119
|
+
title: " Tables ",
|
|
120
|
+
borders: [:all],
|
|
121
|
+
border_style: is_active ? @style_active : @style_inactive
|
|
122
|
+
),
|
|
123
|
+
highlight_style: @style_highlight
|
|
124
|
+
)
|
|
125
|
+
# KEY STEP: Pass the state object!
|
|
126
|
+
frame.render_stateful_widget(list, area, @list_state)
|
|
127
|
+
|
|
128
|
+
# Render Scrollbar
|
|
129
|
+
scrollbar = @tui.scrollbar(
|
|
130
|
+
content_length: 0,
|
|
131
|
+
position: 0,
|
|
132
|
+
orientation: :vertical_right,
|
|
133
|
+
track_symbol: nil,
|
|
134
|
+
thumb_symbol: "▐"
|
|
135
|
+
)
|
|
136
|
+
scrollbar_state = RatatuiRuby::ScrollbarState.new(@tables.size)
|
|
137
|
+
scrollbar_state.position = @list_state.offset
|
|
138
|
+
scrollbar_state.viewport_content_length = area.height - 2
|
|
139
|
+
|
|
140
|
+
frame.render_stateful_widget(scrollbar, area, scrollbar_state)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private def render_table(frame, area)
|
|
144
|
+
is_active = @active_pane == :table
|
|
145
|
+
|
|
146
|
+
# Get current data based on list selection
|
|
147
|
+
current_table = @tables[@list_state.selected || 0]
|
|
148
|
+
rows = @data[current_table]
|
|
149
|
+
|
|
150
|
+
# Render table
|
|
151
|
+
table = @tui.table(
|
|
152
|
+
rows:,
|
|
153
|
+
header: @headers[current_table],
|
|
154
|
+
widths: [
|
|
155
|
+
@tui.constraint_percentage(30),
|
|
156
|
+
@tui.constraint_percentage(40),
|
|
157
|
+
@tui.constraint_percentage(30),
|
|
158
|
+
],
|
|
159
|
+
block: @tui.block(
|
|
160
|
+
title: " #{current_table} Data ",
|
|
161
|
+
borders: [:all],
|
|
162
|
+
border_style: is_active ? @style_active : @style_inactive
|
|
163
|
+
),
|
|
164
|
+
highlight_style: @style_highlight
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
frame.render_stateful_widget(table, area, @table_state)
|
|
168
|
+
|
|
169
|
+
# Render Scrollbar
|
|
170
|
+
scrollbar = @tui.scrollbar(
|
|
171
|
+
content_length: 0,
|
|
172
|
+
position: 0,
|
|
173
|
+
orientation: :vertical_right,
|
|
174
|
+
track_symbol: nil,
|
|
175
|
+
thumb_symbol: "▐"
|
|
176
|
+
)
|
|
177
|
+
scrollbar_state = RatatuiRuby::ScrollbarState.new(rows.size)
|
|
178
|
+
scrollbar_state.position = @table_state.offset
|
|
179
|
+
scrollbar_state.viewport_content_length = area.height - 4 # borders + header + margin
|
|
180
|
+
|
|
181
|
+
frame.render_stateful_widget(scrollbar, area, scrollbar_state)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
private def handle_input
|
|
185
|
+
case @tui.poll_event
|
|
186
|
+
in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
|
|
187
|
+
:quit
|
|
188
|
+
|
|
189
|
+
# Navigation
|
|
190
|
+
in { type: :key, code: "tab" } | { type: :key, code: "right" } | { type: :key, code: "left" }
|
|
191
|
+
@active_pane = (@active_pane == :list) ? :table : :list
|
|
192
|
+
|
|
193
|
+
in { type: :key, code: "down" }
|
|
194
|
+
scroll_active(1)
|
|
195
|
+
|
|
196
|
+
in { type: :key, code: "up" }
|
|
197
|
+
scroll_active(-1)
|
|
198
|
+
|
|
199
|
+
# Mouse Interaction
|
|
200
|
+
in { type: :mouse, kind: "down", x:, y: }
|
|
201
|
+
handle_click(x, y)
|
|
202
|
+
|
|
203
|
+
else
|
|
204
|
+
# no-op
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
private def scroll_active(delta)
|
|
209
|
+
if @active_pane == :list
|
|
210
|
+
i = @list_state.selected || 0
|
|
211
|
+
new_i = (i + delta).clamp(0, @tables.size - 1)
|
|
212
|
+
@list_state.select(new_i)
|
|
213
|
+
# Reset table selection when switching categories
|
|
214
|
+
if i != new_i
|
|
215
|
+
@table_state.select(0)
|
|
216
|
+
@table_state.select_column(nil) # Ensure clean slate
|
|
217
|
+
end
|
|
218
|
+
else
|
|
219
|
+
current_rows = @data[@tables[@list_state.selected || 0]].size
|
|
220
|
+
i = @table_state.selected || 0
|
|
221
|
+
new_i = (i + delta).clamp(0, current_rows - 1)
|
|
222
|
+
@table_state.select(new_i)
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
private def handle_click(x, y)
|
|
227
|
+
if @list_area.contains?(x, y)
|
|
228
|
+
handle_list_click(y)
|
|
229
|
+
elsif @table_area.contains?(x, y)
|
|
230
|
+
handle_table_click(y)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
private def handle_list_click(mouse_y)
|
|
235
|
+
@active_pane = :list
|
|
236
|
+
|
|
237
|
+
# CRITICAL: Read back the offset!
|
|
238
|
+
# Formula: clicked_index = (mouse_y - list_top - border_width) + offset
|
|
239
|
+
offset = @list_state.offset
|
|
240
|
+
list_top = @list_area.y
|
|
241
|
+
border_width = 1 # Top border
|
|
242
|
+
|
|
243
|
+
clicked_row = (mouse_y - list_top - border_width) + offset
|
|
244
|
+
|
|
245
|
+
if clicked_row >= 0 && clicked_row < @tables.size
|
|
246
|
+
@list_state.select(clicked_row)
|
|
247
|
+
@table_state.select(0) # Reset table when category changes
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
private def handle_table_click(mouse_y)
|
|
252
|
+
@active_pane = :table
|
|
253
|
+
|
|
254
|
+
# CRITICAL: Read back the offset!
|
|
255
|
+
# Formula: clicked_index = (mouse_y - table_top - border - header_height - margin) + offset
|
|
256
|
+
offset = @table_state.offset
|
|
257
|
+
table_top = @table_area.y
|
|
258
|
+
border_width = 1
|
|
259
|
+
header_height = 1
|
|
260
|
+
# No header_margin without Row margin
|
|
261
|
+
effective_top = table_top + border_width + header_height
|
|
262
|
+
|
|
263
|
+
clicked_row = (mouse_y - effective_top) + offset
|
|
264
|
+
|
|
265
|
+
current_table_data = @data[@tables[@list_state.selected || 0]]
|
|
266
|
+
if clicked_row >= 0 && clicked_row < current_table_data.size
|
|
267
|
+
@table_state.select(clicked_row)
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
AppStatefulInteraction.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
|
+
# Timeout Demo: Non-Blocking Event Polling
|
|
7
|
+
#
|
|
8
|
+
# This demo shows how to use poll_event with a timeout for game loops
|
|
9
|
+
# and animation systems that need to update at a fixed frame rate
|
|
10
|
+
# regardless of user input.
|
|
11
|
+
#
|
|
12
|
+
# Run: bundle exec ruby examples/timeout_demo.rb
|
|
13
|
+
#
|
|
14
|
+
# Expected behavior:
|
|
15
|
+
# - "Tick..." prints every 100ms continuously
|
|
16
|
+
# - Pressing a key prints "Key Pressed: [key]" immediately
|
|
17
|
+
# - Press 'q' to quit
|
|
18
|
+
|
|
19
|
+
require "bundler/setup"
|
|
20
|
+
require "ratatui_ruby"
|
|
21
|
+
|
|
22
|
+
puts "Timeout Demo - Press 'q' to quit"
|
|
23
|
+
puts "Watch: continuous ticks with responsive key handling"
|
|
24
|
+
puts
|
|
25
|
+
|
|
26
|
+
tick_count = 0
|
|
27
|
+
running = true
|
|
28
|
+
|
|
29
|
+
while running
|
|
30
|
+
# Poll with 100ms timeout (~10 FPS tick rate)
|
|
31
|
+
event = RatatuiRuby.poll_event(timeout: 0.1)
|
|
32
|
+
|
|
33
|
+
if event.none?
|
|
34
|
+
# No input, just tick
|
|
35
|
+
tick_count += 1
|
|
36
|
+
puts "Tick #{tick_count}..."
|
|
37
|
+
elsif event.key?
|
|
38
|
+
puts "Key Pressed: #{event.code}"
|
|
39
|
+
running = false if event.code == "q"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
puts "\nGoodbye!"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Quickstart DSL Verification
|
|
7
|
+
|
|
8
|
+
Verifies the "Idiomatic Session" tutorial in the [Quickstart](../../doc/quickstart.md#idiomatic-session).
|
|
9
|
+
|
|
10
|
+
This example exists as a documentation regression test. It ensures the recommended DSL and session-based workflow remains functional.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
<!-- SYNC:START:app.rb:main -->
|
|
15
|
+
```ruby
|
|
16
|
+
RatatuiRuby.run do |tui|
|
|
17
|
+
loop do
|
|
18
|
+
# 2. Create your UI with methods instead of classes.
|
|
19
|
+
view = tui.paragraph(
|
|
20
|
+
text: "Hello, Ratatui! Press 'q' to quit.",
|
|
21
|
+
alignment: :center,
|
|
22
|
+
block: tui.block(
|
|
23
|
+
title: "My Ruby TUI App",
|
|
24
|
+
title_alignment: :center,
|
|
25
|
+
borders: [:all],
|
|
26
|
+
border_color: "cyan",
|
|
27
|
+
style: { fg: "white" }
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# 3. Use RatatuiRuby methods, too.
|
|
32
|
+
tui.draw do |frame|
|
|
33
|
+
frame.render_widget(view, frame.area)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# 4. Poll for events with pattern matching
|
|
37
|
+
case tui.poll_event
|
|
38
|
+
in { type: :key, code: "q" }
|
|
39
|
+
break
|
|
40
|
+
else
|
|
41
|
+
# Ignore other events
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
```
|
|
46
|
+
<!-- SYNC:END -->
|
|
47
|
+
|
|
48
|
+

|
|
@@ -10,6 +10,7 @@ require "ratatui_ruby"
|
|
|
10
10
|
class VerifyQuickstartDsl
|
|
11
11
|
def run
|
|
12
12
|
# 1. Initialize the terminal, start the run loop, and ensure the terminal is restored.
|
|
13
|
+
# [SYNC:START:main]
|
|
13
14
|
RatatuiRuby.run do |tui|
|
|
14
15
|
loop do
|
|
15
16
|
# 2. Create your UI with methods instead of classes.
|
|
@@ -39,6 +40,7 @@ class VerifyQuickstartDsl
|
|
|
39
40
|
end
|
|
40
41
|
end
|
|
41
42
|
end
|
|
43
|
+
# [SYNC:END:main]
|
|
42
44
|
end
|
|
43
45
|
end
|
|
44
46
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Quickstart Layout Verification
|
|
7
|
+
|
|
8
|
+
Verifies the "Adding Layouts" tutorial in the [Quickstart](../../doc/quickstart.md#adding-layouts).
|
|
9
|
+
|
|
10
|
+
This example exists as a documentation regression test. It ensures the layout and constraints examples remain functional.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
<!-- SYNC:START:app.rb:main -->
|
|
15
|
+
```ruby
|
|
16
|
+
loop do
|
|
17
|
+
tui.draw do |frame|
|
|
18
|
+
# 1. Split the screen
|
|
19
|
+
top, bottom = tui.layout_split(
|
|
20
|
+
frame.area,
|
|
21
|
+
direction: :vertical,
|
|
22
|
+
constraints: [
|
|
23
|
+
tui.constraint_percentage(75),
|
|
24
|
+
tui.constraint_percentage(25),
|
|
25
|
+
]
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# 2. Render Top Widget
|
|
29
|
+
frame.render_widget(
|
|
30
|
+
tui.paragraph(
|
|
31
|
+
text: "Hello, Ratatui!",
|
|
32
|
+
alignment: :center,
|
|
33
|
+
block: tui.block(title: "Content", borders: [:all], border_color: "cyan")
|
|
34
|
+
),
|
|
35
|
+
top
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# 3. Render Bottom Widget with Styled Text
|
|
39
|
+
# We use a Line of Spans to style specific characters
|
|
40
|
+
text_line = tui.text_line(
|
|
41
|
+
spans: [
|
|
42
|
+
tui.text_span(content: "Press '"),
|
|
43
|
+
tui.text_span(
|
|
44
|
+
content: "q",
|
|
45
|
+
style: tui.style(modifiers: [:bold, :underlined])
|
|
46
|
+
),
|
|
47
|
+
tui.text_span(content: "' to quit."),
|
|
48
|
+
],
|
|
49
|
+
alignment: :center
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
frame.render_widget(
|
|
53
|
+
tui.paragraph(
|
|
54
|
+
text: text_line,
|
|
55
|
+
block: tui.block(title: "Controls", borders: [:all])
|
|
56
|
+
),
|
|
57
|
+
bottom
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
case tui.poll_event
|
|
62
|
+
in { type: :key, code: "q" }
|
|
63
|
+
break
|
|
64
|
+
else
|
|
65
|
+
# Ignore other events
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
```
|
|
69
|
+
<!-- SYNC:END -->
|
|
70
|
+
|
|
71
|
+

|
|
@@ -10,6 +10,7 @@ require "ratatui_ruby"
|
|
|
10
10
|
class VerifyQuickstartLayout
|
|
11
11
|
def run
|
|
12
12
|
RatatuiRuby.run do |tui|
|
|
13
|
+
# [SYNC:START:main]
|
|
13
14
|
loop do
|
|
14
15
|
tui.draw do |frame|
|
|
15
16
|
# 1. Split the screen
|
|
@@ -62,6 +63,7 @@ class VerifyQuickstartLayout
|
|
|
62
63
|
# Ignore other events
|
|
63
64
|
end
|
|
64
65
|
end
|
|
66
|
+
# [SYNC:END:main]
|
|
65
67
|
end
|
|
66
68
|
end
|
|
67
69
|
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Quickstart Lifecycle Verification
|
|
7
|
+
|
|
8
|
+
Verifies the "Basic Application" tutorial in the [Quickstart](../../doc/quickstart.md#basic-application).
|
|
9
|
+
|
|
10
|
+
This example exists as a documentation regression test. It ensures the core lifecycle example presented to new users remains functional.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
<!-- SYNC:START:app.rb:main -->
|
|
15
|
+
```ruby
|
|
16
|
+
# 1. Initialize the terminal
|
|
17
|
+
RatatuiRuby.init_terminal
|
|
18
|
+
|
|
19
|
+
begin
|
|
20
|
+
# The Main Loop
|
|
21
|
+
loop do
|
|
22
|
+
# 2. Create your UI (Immediate Mode)
|
|
23
|
+
# We define a Paragraph widget inside a Block with a title and borders.
|
|
24
|
+
view = RatatuiRuby::Paragraph.new(
|
|
25
|
+
text: "Hello, Ratatui! Press 'q' to quit.",
|
|
26
|
+
alignment: :center,
|
|
27
|
+
block: RatatuiRuby::Block.new(
|
|
28
|
+
title: "My Ruby TUI App",
|
|
29
|
+
title_alignment: :center,
|
|
30
|
+
borders: [:all],
|
|
31
|
+
border_color: "cyan",
|
|
32
|
+
style: { fg: "white" }
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# 3. Draw the UI
|
|
37
|
+
RatatuiRuby.draw do |frame|
|
|
38
|
+
frame.render_widget(view, frame.area)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# 4. Poll for events
|
|
42
|
+
case RatatuiRuby.poll_event
|
|
43
|
+
in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
|
|
44
|
+
break
|
|
45
|
+
else
|
|
46
|
+
nil
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
ensure
|
|
50
|
+
# 5. Restore the terminal to its original state
|
|
51
|
+
RatatuiRuby.restore_terminal
|
|
52
|
+
end
|
|
53
|
+
```
|
|
54
|
+
<!-- SYNC:END -->
|
|
55
|
+
|
|
56
|
+

|
|
@@ -9,6 +9,7 @@ require "ratatui_ruby"
|
|
|
9
9
|
|
|
10
10
|
class VerifyQuickstartLifecycle
|
|
11
11
|
def run
|
|
12
|
+
# [SYNC:START:main]
|
|
12
13
|
# 1. Initialize the terminal
|
|
13
14
|
RatatuiRuby.init_terminal
|
|
14
15
|
|
|
@@ -35,13 +36,18 @@ class VerifyQuickstartLifecycle
|
|
|
35
36
|
end
|
|
36
37
|
|
|
37
38
|
# 4. Poll for events
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
case RatatuiRuby.poll_event
|
|
40
|
+
in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
|
|
41
|
+
break
|
|
42
|
+
else
|
|
43
|
+
nil
|
|
44
|
+
end
|
|
40
45
|
end
|
|
41
46
|
ensure
|
|
42
47
|
# 5. Restore the terminal to its original state
|
|
43
48
|
RatatuiRuby.restore_terminal
|
|
44
49
|
end
|
|
50
|
+
# [SYNC:END:main]
|
|
45
51
|
end
|
|
46
52
|
end
|
|
47
53
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# README Usage Verification
|
|
7
|
+
|
|
8
|
+
Verifies the primary usage example in the project [README](../../README.md#usage).
|
|
9
|
+
|
|
10
|
+
This example exists as a documentation regression test. It ensures that the very first code snippet a user sees actually works.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
<!-- SYNC:START:app.rb:main -->
|
|
15
|
+
```ruby
|
|
16
|
+
RatatuiRuby.run do |tui|
|
|
17
|
+
loop do
|
|
18
|
+
tui.draw do |frame|
|
|
19
|
+
frame.render_widget(
|
|
20
|
+
tui.paragraph(
|
|
21
|
+
text: "Hello, Ratatui! Press 'q' to quit.",
|
|
22
|
+
alignment: :center,
|
|
23
|
+
block: tui.block(
|
|
24
|
+
title: "My Ruby TUI App",
|
|
25
|
+
borders: [:all],
|
|
26
|
+
border_color: "cyan"
|
|
27
|
+
)
|
|
28
|
+
),
|
|
29
|
+
frame.area
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
case tui.poll_event
|
|
33
|
+
in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
|
|
34
|
+
break
|
|
35
|
+
else
|
|
36
|
+
nil
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
```
|
|
41
|
+
<!-- SYNC:END -->
|
|
42
|
+
|
|
43
|
+

|
|
@@ -8,6 +8,7 @@ $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
|
8
8
|
require "ratatui_ruby"
|
|
9
9
|
class VerifyReadmeUsage
|
|
10
10
|
def run
|
|
11
|
+
# [SYNC:START:main]
|
|
11
12
|
RatatuiRuby.run do |tui|
|
|
12
13
|
loop do
|
|
13
14
|
tui.draw do |frame|
|
|
@@ -24,10 +25,15 @@ class VerifyReadmeUsage
|
|
|
24
25
|
frame.area
|
|
25
26
|
)
|
|
26
27
|
end
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
case tui.poll_event
|
|
29
|
+
in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
|
|
30
|
+
break
|
|
31
|
+
else
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
29
34
|
end
|
|
30
35
|
end
|
|
36
|
+
# [SYNC:END:main]
|
|
31
37
|
end
|
|
32
38
|
end
|
|
33
39
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# BarChart Widget Example
|
|
7
|
+
|
|
8
|
+
Visualizes categorical data with interactive attribute cycling.
|
|
9
|
+
|
|
10
|
+
Comparing magnitudes in raw tables requires mental arithmetic. Bar charts make these comparisons instant and intuitive.
|
|
11
|
+
|
|
12
|
+
## Features Demonstrated
|
|
13
|
+
|
|
14
|
+
- **Data Formats**: Supports simple Hashes, Arrays with individual styles, and Groups (stacked/grouped bars).
|
|
15
|
+
- **Orientation**: Switch between Vertical and Horizontal layouts.
|
|
16
|
+
- **Customization**:
|
|
17
|
+
- Adjustable bar widths and gaps.
|
|
18
|
+
- Custom characters for bars (ASCII art support).
|
|
19
|
+
- Detailed styling for labels and values.
|
|
20
|
+
- **Mini Mode**: Compact rendering for dashboard widgets.
|
|
21
|
+
|
|
22
|
+
## Hotkeys
|
|
23
|
+
|
|
24
|
+
- **d**: Cycle Data Source (`data`)
|
|
25
|
+
- **v**: Toggle Direction (`direction`)
|
|
26
|
+
- **w**: Adjust Bar Width (`bar_width`)
|
|
27
|
+
- **a**: Adjust Bar Gap (`bar_gap`)
|
|
28
|
+
- **g**: Adjust Group Gap (`group_gap`)
|
|
29
|
+
- **b**: Cycle Bar Character Set (`bar_set`)
|
|
30
|
+
- **s**: Cycle Chart Style (`style`)
|
|
31
|
+
- **x**: Cycle Label Style (`label_style`)
|
|
32
|
+
- **z**: Cycle Value Style (`value_style`)
|
|
33
|
+
- **m**: Toggle Mini Mode (Compact View)
|
|
34
|
+
- **q**: Quit
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
ruby examples/widget_barchart_demo/app.rb
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Learning Outcomes
|
|
43
|
+
|
|
44
|
+
Use this example if you need to...
|
|
45
|
+
- Visualize categorical data (e.g., sales by quarter, CPU usage by core).
|
|
46
|
+
- Create "stats" dashboards with compact visualizations.
|
|
47
|
+
- Understand how `RatatuiRuby::BarChart` handles different data structures.
|
|
48
|
+
|
|
49
|
+

|
|
@@ -23,11 +23,11 @@ require "ratatui_ruby"
|
|
|
23
23
|
# rdoc-image:/doc/images/widget_barchart_demo.png
|
|
24
24
|
class WidgetBarchartDemo
|
|
25
25
|
def initialize
|
|
26
|
-
@data_index =
|
|
26
|
+
@data_index = 2
|
|
27
27
|
@styles = nil # Initialized in run
|
|
28
|
-
@style_index =
|
|
29
|
-
@label_style_index =
|
|
30
|
-
@value_style_index =
|
|
28
|
+
@style_index = 3
|
|
29
|
+
@label_style_index = 3
|
|
30
|
+
@value_style_index = 3
|
|
31
31
|
@bar_sets = [
|
|
32
32
|
{ name: "Default", set: nil },
|
|
33
33
|
{ name: "Numbers (Short)", set: { 8 => "8", 7 => "7", 6 => "6", 5 => "5", 4 => "4", 3 => "3", 2 => "2", 1 => "1", 0 => "0" } },
|
|
@@ -38,7 +38,7 @@ class WidgetBarchartDemo
|
|
|
38
38
|
@direction = :vertical
|
|
39
39
|
@bar_width = 8
|
|
40
40
|
@bar_gap = 1
|
|
41
|
-
@group_gap =
|
|
41
|
+
@group_gap = 2
|
|
42
42
|
@height_mode = :full
|
|
43
43
|
@hotkey_style = nil
|
|
44
44
|
end
|