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,29 @@
|
|
|
1
|
+
# Center Widget Demo
|
|
2
|
+
<!--
|
|
3
|
+
SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
5
|
+
-->
|
|
6
|
+
|
|
7
|
+
This example demonstrates the `Center` widget, which positions a child widget in the center of the available area.
|
|
8
|
+
|
|
9
|
+
## Key Concepts
|
|
10
|
+
|
|
11
|
+
- **Centering**: The widget automatically calculates the necessary padding to center its child.
|
|
12
|
+
- **Sizing**: You can control the size of the centered area using `width_percent` and `height_percent`.
|
|
13
|
+
- **Composition**: The `Center` widget wraps another widget (the child), making it easy to compose layouts.
|
|
14
|
+
|
|
15
|
+
## Controls
|
|
16
|
+
|
|
17
|
+
| Key | Action |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `←` / `→` | Decrease / Increase width percentage |
|
|
20
|
+
| `↑` / `↓` | Increase / Decrease height percentage |
|
|
21
|
+
| `q` | Quit |
|
|
22
|
+
|
|
23
|
+
## Screenshot
|
|
24
|
+
|
|
25
|
+

|
|
26
|
+
|
|
27
|
+
## Source Code
|
|
28
|
+
|
|
29
|
+
- [app.rb](app.rb)
|
|
@@ -0,0 +1,116 @@
|
|
|
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
|
+
# Demo: Center Widget
|
|
10
|
+
# Demonstrates how to center content horizontally and vertically
|
|
11
|
+
# with adjustable width/height percentages.
|
|
12
|
+
class WidgetCenterDemo
|
|
13
|
+
def initialize
|
|
14
|
+
@width_percent = 50
|
|
15
|
+
@height_percent = 50
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def run
|
|
19
|
+
RatatuiRuby.run do |tui|
|
|
20
|
+
@tui = tui
|
|
21
|
+
loop do
|
|
22
|
+
render
|
|
23
|
+
break if handle_input == :quit
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private def render
|
|
29
|
+
@tui.draw do |frame|
|
|
30
|
+
layout = @tui.layout_split(
|
|
31
|
+
frame.area,
|
|
32
|
+
direction: :vertical,
|
|
33
|
+
constraints: [
|
|
34
|
+
@tui.constraint_fill(1),
|
|
35
|
+
@tui.constraint_length(3),
|
|
36
|
+
]
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# 1. Main Area
|
|
40
|
+
# Background block frames the centered content
|
|
41
|
+
bg_block = @tui.block(
|
|
42
|
+
title: "Center Widget Demo",
|
|
43
|
+
borders: [:all],
|
|
44
|
+
style: @tui.style(fg: :gray)
|
|
45
|
+
)
|
|
46
|
+
frame.render_widget(bg_block, layout[0])
|
|
47
|
+
|
|
48
|
+
# 2. Centered Content
|
|
49
|
+
# The content itself is just a block with some text
|
|
50
|
+
content = @tui.paragraph(
|
|
51
|
+
text: [
|
|
52
|
+
@tui.text_line(
|
|
53
|
+
spans: [
|
|
54
|
+
@tui.text_span(content: "Centered Area", style: @tui.style(modifiers: [:bold])),
|
|
55
|
+
],
|
|
56
|
+
alignment: :center
|
|
57
|
+
),
|
|
58
|
+
@tui.text_line(spans: []),
|
|
59
|
+
@tui.text_line(spans: [@tui.text_span(content: "Width: #{@width_percent}%", style: @tui.style(fg: :cyan))], alignment: :center),
|
|
60
|
+
@tui.text_line(spans: [@tui.text_span(content: "Height: #{@height_percent}%", style: @tui.style(fg: :magenta))], alignment: :center),
|
|
61
|
+
],
|
|
62
|
+
block: @tui.block(
|
|
63
|
+
title: "Child Widget",
|
|
64
|
+
borders: [:all],
|
|
65
|
+
style: @tui.style(fg: :white)
|
|
66
|
+
),
|
|
67
|
+
alignment: :center
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Create the Center widget
|
|
71
|
+
center_widget = @tui.center(
|
|
72
|
+
child: content,
|
|
73
|
+
width_percent: @width_percent,
|
|
74
|
+
height_percent: @height_percent
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Render center widget into the main layout area
|
|
78
|
+
frame.render_widget(center_widget, layout[0])
|
|
79
|
+
|
|
80
|
+
# 3. Controls
|
|
81
|
+
control_text = @tui.paragraph(
|
|
82
|
+
text: [
|
|
83
|
+
@tui.text_line(spans: [
|
|
84
|
+
@tui.text_span(content: "←/→", style: @tui.style(modifiers: [:bold, :underlined])),
|
|
85
|
+
@tui.text_span(content: ": Width "),
|
|
86
|
+
@tui.text_span(content: "↑/↓", style: @tui.style(modifiers: [:bold, :underlined])),
|
|
87
|
+
@tui.text_span(content: ": Height "),
|
|
88
|
+
@tui.text_span(content: "q", style: @tui.style(modifiers: [:bold, :underlined])),
|
|
89
|
+
@tui.text_span(content: ": Quit"),
|
|
90
|
+
]),
|
|
91
|
+
],
|
|
92
|
+
block: @tui.block(borders: [:top], style: @tui.style(bg: :black))
|
|
93
|
+
)
|
|
94
|
+
frame.render_widget(control_text, layout[1])
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def handle_input
|
|
99
|
+
case @tui.poll_event
|
|
100
|
+
in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
|
|
101
|
+
:quit
|
|
102
|
+
in { type: :key, code: "left" }
|
|
103
|
+
@width_percent = [@width_percent - 5, 5].max
|
|
104
|
+
in { type: :key, code: "right" }
|
|
105
|
+
@width_percent = [@width_percent + 5, 100].min
|
|
106
|
+
in { type: :key, code: "up" }
|
|
107
|
+
@height_percent = [@height_percent + 5, 100].min
|
|
108
|
+
in { type: :key, code: "down" }
|
|
109
|
+
@height_percent = [@height_percent - 5, 5].max
|
|
110
|
+
else
|
|
111
|
+
# Ignore other events
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
WidgetCenterDemo.new.run if __FILE__ == $0
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Chart Widget Example
|
|
7
|
+
|
|
8
|
+
Demonstrates Cartesian plotting with interactive styling and configuration.
|
|
9
|
+
|
|
10
|
+
Trends and patterns are invisible in raw logs. Charts visualize X/Y datasets to reveal the story behind the data.
|
|
11
|
+
|
|
12
|
+
## Features Demonstrated
|
|
13
|
+
|
|
14
|
+
- **Dataset Types**: Line charts and Scatter plots.
|
|
15
|
+
- **Markers**: Braille patterns, dots, blocks, and bars.
|
|
16
|
+
- **Axis Configuration**: Controlling labels, bounds, and alignment (Left/Center/Right).
|
|
17
|
+
- **Legend**: Positioning the legend in any of the four corners or hiding it based on constraints.
|
|
18
|
+
|
|
19
|
+
## Hotkeys
|
|
20
|
+
|
|
21
|
+
- **m**: Cycle Marker Type (`marker`)
|
|
22
|
+
- **s**: Cycle Dataset Style (`style`)
|
|
23
|
+
- **x**: Cycle X-Axis Alignment (`labels_alignment`)
|
|
24
|
+
- **y**: Cycle Y-Axis Alignment (`labels_alignment`)
|
|
25
|
+
- **l**: Cycle Legend Position (`legend_position`)
|
|
26
|
+
- **q**: Quit
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
ruby examples/widget_chart_demo/app.rb
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Learning Outcomes
|
|
35
|
+
|
|
36
|
+
Use this example if you need to...
|
|
37
|
+
- Plot real-time data monitoring (CPU history, request latency).
|
|
38
|
+
- Visualize mathematical functions.
|
|
39
|
+
- Compare multiple datasets on the same axis.
|
|
40
|
+
|
|
41
|
+

|
|
@@ -53,6 +53,11 @@ class WidgetChartDemo
|
|
|
53
53
|
@tui = tui
|
|
54
54
|
init_styles
|
|
55
55
|
|
|
56
|
+
# Support seeded random for deterministic testing
|
|
57
|
+
# Set RATA_SEED=42 for reproducible scatter plot data
|
|
58
|
+
seed = ENV.fetch("RATA_SEED", nil)
|
|
59
|
+
@rng = seed ? Random.new(seed.to_i) : Random.new
|
|
60
|
+
|
|
56
61
|
@marker_index = 0
|
|
57
62
|
@dataset_style_index = 0
|
|
58
63
|
@x_alignment_index = 1
|
|
@@ -89,9 +94,9 @@ class WidgetChartDemo
|
|
|
89
94
|
[x, Math.sin(x)]
|
|
90
95
|
end
|
|
91
96
|
|
|
92
|
-
# Scatter: Random points
|
|
97
|
+
# Scatter: Random points (deterministic when RATA_SEED is set)
|
|
93
98
|
scatter_data = (0..20).map do |_|
|
|
94
|
-
[rand(0.0..10.0), rand(-1.0..1.0)]
|
|
99
|
+
[@rng.rand(0.0..10.0), @rng.rand(-1.0..1.0)]
|
|
95
100
|
end
|
|
96
101
|
|
|
97
102
|
style = @dataset_styles[@dataset_style_index][:style]
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Gauge Widget Example
|
|
7
|
+
|
|
8
|
+
Demonstrates progress bars with interactive configuration.
|
|
9
|
+
|
|
10
|
+
Long-running tasks create anxiety. Users need to know the system is working. Gauges provide visual feedback on completion status.
|
|
11
|
+
|
|
12
|
+
## Features Demonstrated
|
|
13
|
+
|
|
14
|
+
- **Progress styles**: standard block characters or Unicode bars.
|
|
15
|
+
- **Labels**: Customizing the text overlay (Percentage, Ratio, etc.).
|
|
16
|
+
- **Styling**: Independent control of the filled gauge color and the background track.
|
|
17
|
+
- **Thresholds**: Implementing multi-colored gauges based on values.
|
|
18
|
+
|
|
19
|
+
## Hotkeys
|
|
20
|
+
|
|
21
|
+
- **Arrows (←/→)**: Adjust Ratio (`ratio`)
|
|
22
|
+
- **g**: Cycle Gauge Color (`gauge_style`)
|
|
23
|
+
- **b**: Cycle Background Style (`style`)
|
|
24
|
+
- **u**: Toggle Unicode Mode (`use_unicode`)
|
|
25
|
+
- **l**: Cycle Label Mode (`label`)
|
|
26
|
+
- **q**: Quit
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
ruby examples/widget_gauge_demo/app.rb
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Learning Outcomes
|
|
35
|
+
|
|
36
|
+
Use this example if you need to...
|
|
37
|
+
- Show download or upload progress.
|
|
38
|
+
- Visualize resource quotas (disk space, memory usage).
|
|
39
|
+
- Create "health bars" or status indicators.
|
|
40
|
+
|
|
41
|
+

|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Layout Split Example
|
|
7
|
+
|
|
8
|
+
Demonstrates dynamic geometry management with constraints and flex modes.
|
|
9
|
+
|
|
10
|
+
Terminal screens vary in size. Hardcoded layouts break. `Layout.split` manages space dynamically, ensuring your interface adapts to any window dimension.
|
|
11
|
+
|
|
12
|
+
## Features Demonstrated
|
|
13
|
+
|
|
14
|
+
- **Constraints**:
|
|
15
|
+
- `Fill(n)`: Takes available space proportional to `n`.
|
|
16
|
+
- `Length(n)`: Fixed number of cells.
|
|
17
|
+
- `Percentage(n)`: Percentage of the parent area.
|
|
18
|
+
- `Min(n)`: At least `n` cells.
|
|
19
|
+
- `Ratio(x, y)`: `x/y` of the parent area.
|
|
20
|
+
- **Flex Modes**: Controlling how extra space is distributed (`Start`, `End`, `Center`, `SpaceBetween`, etc.).
|
|
21
|
+
- **Direction**: Splitting Vertically vs Horizontally.
|
|
22
|
+
|
|
23
|
+
## Hotkeys
|
|
24
|
+
|
|
25
|
+
- **d**: Toggle Direction (`direction`)
|
|
26
|
+
- **f**: Cycle Flex Mode (`flex`)
|
|
27
|
+
- **c**: Cycle Constraint Set (`constraints`)
|
|
28
|
+
- **q**: Quit
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
ruby examples/widget_layout_split/app.rb
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Learning Outcomes
|
|
37
|
+
|
|
38
|
+
Use this example if you need to...
|
|
39
|
+
- Build responsive dashboards.
|
|
40
|
+
- Create 3-column layouts where the middle content fills remaining space.
|
|
41
|
+
- Center a modal dialog on the screen.
|
|
42
|
+
- Distribute buttons evenly across a control bar.
|
|
43
|
+
|
|
44
|
+

|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Line Gauge Widget Example
|
|
7
|
+
|
|
8
|
+
Demonstrates compact progress bars for constrained spaces.
|
|
9
|
+
|
|
10
|
+
Standard block gauges take up vertical space. Sometimes you only have one line to show status. The `LineGauge` provides a compact, high-density progress indicator.
|
|
11
|
+
|
|
12
|
+
## Features Demonstrated
|
|
13
|
+
|
|
14
|
+
- **Compact Rendering**: Visualizing progress in a single character height.
|
|
15
|
+
- **Custom Symbols**: Replacing the standard line with Blocks, Shades, Dashes, or ASCII characters.
|
|
16
|
+
- **Styling**: Independent styling for the filled (progress) and unfilled (track) portions.
|
|
17
|
+
|
|
18
|
+
## Hotkeys
|
|
19
|
+
|
|
20
|
+
- **Arrows (←/→)**: Adjust Ratio (`ratio`)
|
|
21
|
+
- **f**: Cycle Filled Symbol (`filled_symbol`)
|
|
22
|
+
- **u**: Cycle Unfilled Symbol (`unfilled_symbol`)
|
|
23
|
+
- **c**: Cycle Filled Color (`filled_style`)
|
|
24
|
+
- **x**: Cycle Unfilled Color (`unfilled_style`)
|
|
25
|
+
- **b**: Cycle Base Style (`style`)
|
|
26
|
+
- **q**: Cycle Quit
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
ruby examples/widget_line_gauge_demo/app.rb
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Learning Outcomes
|
|
35
|
+
|
|
36
|
+
Use this example if you need to...
|
|
37
|
+
- Add a progress bar to a list item or table row.
|
|
38
|
+
- Create a status line at the bottom of the screen.
|
|
39
|
+
- Show multiple metrics (CPU, RAM, Net) in a compact list.
|
|
40
|
+
|
|
41
|
+

|
|
@@ -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
|
+
# List Widget Example
|
|
7
|
+
|
|
8
|
+
Demonstrates a selectable list with extensive configuration options.
|
|
9
|
+
|
|
10
|
+
Lists are the workhorse of terminal interfaces. Managing selection state, scrolling windows, and highlight styles logic is complex. The `List` widget handles all of this.
|
|
11
|
+
|
|
12
|
+
## Features Demonstrated
|
|
13
|
+
|
|
14
|
+
- **Scrolling**: Automatically handles lists larger than the view area.
|
|
15
|
+
- **Selection**: Maintains selected index and supports "no selection" state.
|
|
16
|
+
- **Highlighting**: Custom styles and symbols (e.g., `>>`) for the selected item.
|
|
17
|
+
- **Offset Modes**: Manual control over the scroll offset vs automatic "scroll to selection" behavior.
|
|
18
|
+
- **Scroll Padding**: Keeping a margin of items visible above/below the selection.
|
|
19
|
+
|
|
20
|
+
## Hotkeys
|
|
21
|
+
|
|
22
|
+
- **i**: Cycle Item Data (`items`)
|
|
23
|
+
- **Arrow Keys (↑/↓)**: Navigate (`selected_index`)
|
|
24
|
+
- **x**: Toggle Selection (`selected_index`)
|
|
25
|
+
- **h**: Cycle Highlight Style (`highlight_style`)
|
|
26
|
+
- **y**: Cycle Highlight Symbol (`highlight_symbol`)
|
|
27
|
+
- **d**: Toggle Direction (`direction`)
|
|
28
|
+
- **s**: Cycle Highlight Spacing (`highlight_spacing`)
|
|
29
|
+
- **p**: Cycle Scroll Padding (`scroll_padding`)
|
|
30
|
+
- **b**: Cycle Base Style (`style`)
|
|
31
|
+
- **r**: Toggle Repeat Highlight Symbol (`repeat_highlight_symbol`)
|
|
32
|
+
- **o**: Cycle Offset Mode (`offset`)
|
|
33
|
+
- **q**: Quit
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
ruby examples/widget_list_demo/app.rb
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Learning Outcomes
|
|
42
|
+
|
|
43
|
+
Use this example if you need to...
|
|
44
|
+
- Create a file explorer.
|
|
45
|
+
- Build a navigation menu.
|
|
46
|
+
- Display a log where users can scroll back to read history.
|
|
47
|
+
- Implement "infinite select" behaviors.
|
|
48
|
+
|
|
49
|
+

|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
7
|
require "ratatui_ruby"
|
|
8
|
+
require "faker" # Use Faker for large, realistic datasets
|
|
8
9
|
|
|
9
10
|
# Demonstrates a selectable list of items with interactive attribute cycling.
|
|
10
11
|
#
|
|
@@ -24,111 +25,18 @@ require "ratatui_ruby"
|
|
|
24
25
|
class WidgetListDemo
|
|
25
26
|
# Initializes the demo with example data and default configuration.
|
|
26
27
|
def initialize
|
|
27
|
-
|
|
28
|
+
Faker::Config.random = Random.new(12345)
|
|
29
|
+
@selected_index = 6 # Start at C# to avoid highlighting the rich text examples
|
|
30
|
+
@tui_for_setup = nil
|
|
28
31
|
|
|
29
32
|
@item_sets = [
|
|
30
|
-
{
|
|
31
|
-
name: "Large List",
|
|
32
|
-
items: (1..200).map { |i| "Item #{i}" },
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name: "Colors",
|
|
36
|
-
items: [
|
|
37
|
-
"Red",
|
|
38
|
-
"Orange",
|
|
39
|
-
"Yellow",
|
|
40
|
-
"Green",
|
|
41
|
-
"Cyan",
|
|
42
|
-
"Blue",
|
|
43
|
-
"Indigo",
|
|
44
|
-
"Violet",
|
|
45
|
-
"Scarlet",
|
|
46
|
-
"Crimson",
|
|
47
|
-
"Maroon",
|
|
48
|
-
"Brown",
|
|
49
|
-
"Tan",
|
|
50
|
-
"Beige",
|
|
51
|
-
"Khaki",
|
|
52
|
-
"Gold",
|
|
53
|
-
"Silver",
|
|
54
|
-
"White",
|
|
55
|
-
"Gray",
|
|
56
|
-
"Black",
|
|
57
|
-
"Pink",
|
|
58
|
-
"Magenta",
|
|
59
|
-
"Turquoise",
|
|
60
|
-
"Teal",
|
|
61
|
-
"Coral",
|
|
62
|
-
"Salmon",
|
|
63
|
-
"Peach",
|
|
64
|
-
"Lavender",
|
|
65
|
-
"Lilac",
|
|
66
|
-
"Olive",
|
|
67
|
-
"Lime",
|
|
68
|
-
"Navy",
|
|
69
|
-
"Charcoal",
|
|
70
|
-
"Ivory",
|
|
71
|
-
"Azure",
|
|
72
|
-
],
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
name: "Fruits",
|
|
76
|
-
items: [
|
|
77
|
-
"Apple",
|
|
78
|
-
"Apricot",
|
|
79
|
-
"Avocado",
|
|
80
|
-
"Banana",
|
|
81
|
-
"Blueberry",
|
|
82
|
-
"Blackberry",
|
|
83
|
-
"Cherry",
|
|
84
|
-
"Cranberry",
|
|
85
|
-
"Cucumber",
|
|
86
|
-
"Date",
|
|
87
|
-
"Dragonfruit",
|
|
88
|
-
"Elderberry",
|
|
89
|
-
"Fig",
|
|
90
|
-
"Grape",
|
|
91
|
-
"Grapefruit",
|
|
92
|
-
"Guava",
|
|
93
|
-
"Honeydew",
|
|
94
|
-
"Huckleberry",
|
|
95
|
-
"Jackfruit",
|
|
96
|
-
"Kiwi",
|
|
97
|
-
"Kumquat",
|
|
98
|
-
"Lemon",
|
|
99
|
-
"Lime",
|
|
100
|
-
"Lychee",
|
|
101
|
-
"Mango",
|
|
102
|
-
"Melon",
|
|
103
|
-
"Mulberry",
|
|
104
|
-
"Nectarine",
|
|
105
|
-
"Olive",
|
|
106
|
-
"Orange",
|
|
107
|
-
"Papaya",
|
|
108
|
-
"Passion Fruit",
|
|
109
|
-
"Peach",
|
|
110
|
-
"Pear",
|
|
111
|
-
"Persimmon",
|
|
112
|
-
"Pineapple",
|
|
113
|
-
"Plum",
|
|
114
|
-
"Pomegranate",
|
|
115
|
-
"Prune",
|
|
116
|
-
"Rambutan",
|
|
117
|
-
"Raspberry",
|
|
118
|
-
"Starfruit",
|
|
119
|
-
"Strawberry",
|
|
120
|
-
"Tangerine",
|
|
121
|
-
"Watermelon",
|
|
122
|
-
"Ugli Fruit",
|
|
123
|
-
],
|
|
124
|
-
},
|
|
125
33
|
{
|
|
126
34
|
name: "Programming",
|
|
127
35
|
items: [
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
36
|
+
:ruby_styled, # Will be replaced with rich text in run()
|
|
37
|
+
:rust_styled, # Will be replaced with rich text in run()
|
|
38
|
+
:python_styled, # Will be replaced with rich text in run()
|
|
39
|
+
:javascript_styled, # Will be replaced with rich text in run()
|
|
132
40
|
"Go",
|
|
133
41
|
"C++",
|
|
134
42
|
"C#",
|
|
@@ -175,6 +83,24 @@ class WidgetListDemo
|
|
|
175
83
|
"BASIC",
|
|
176
84
|
],
|
|
177
85
|
},
|
|
86
|
+
{
|
|
87
|
+
name: "Large List",
|
|
88
|
+
items: (1..200).map { |i| "Item #{i}" },
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: "Colors",
|
|
92
|
+
items: begin
|
|
93
|
+
Faker::Color.unique.clear
|
|
94
|
+
Array.new(100) { Faker::Color.color_name }
|
|
95
|
+
end,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "Fruits",
|
|
99
|
+
items: begin
|
|
100
|
+
Faker::Food.unique.clear
|
|
101
|
+
Array.new(100) { Faker::Food.fruits }
|
|
102
|
+
end,
|
|
103
|
+
},
|
|
178
104
|
]
|
|
179
105
|
@item_set_index = 0
|
|
180
106
|
|
|
@@ -192,7 +118,7 @@ class WidgetListDemo
|
|
|
192
118
|
{ name: "Always", spacing: :always },
|
|
193
119
|
{ name: "Never", spacing: :never },
|
|
194
120
|
]
|
|
195
|
-
@highlight_spacing_index =
|
|
121
|
+
@highlight_spacing_index = 1
|
|
196
122
|
|
|
197
123
|
@repeat_modes = [
|
|
198
124
|
{ name: "Off", repeat: false },
|
|
@@ -205,7 +131,15 @@ class WidgetListDemo
|
|
|
205
131
|
{ name: "1 item", padding: 1 },
|
|
206
132
|
{ name: "2 items", padding: 2 },
|
|
207
133
|
]
|
|
208
|
-
@scroll_padding_index =
|
|
134
|
+
@scroll_padding_index = 1
|
|
135
|
+
|
|
136
|
+
# Offset mode configurations to demonstrate offset + selection interaction
|
|
137
|
+
@offset_modes = [
|
|
138
|
+
{ name: "Auto (No Offset)", offset: nil, allow_selection: true },
|
|
139
|
+
{ name: "Offset Only", offset: 10, allow_selection: false },
|
|
140
|
+
{ name: "Selection + Offset (Conflict)", offset: 0, allow_selection: true },
|
|
141
|
+
]
|
|
142
|
+
@offset_mode_index = 0
|
|
209
143
|
end
|
|
210
144
|
|
|
211
145
|
# Runs the demo application.
|
|
@@ -214,8 +148,45 @@ class WidgetListDemo
|
|
|
214
148
|
def run
|
|
215
149
|
RatatuiRuby.run do |tui|
|
|
216
150
|
@tui = tui
|
|
151
|
+
|
|
152
|
+
# Create rich text for "Ruby" - each letter with a different red style
|
|
153
|
+
ruby_line = @tui.text_line(spans: [
|
|
154
|
+
@tui.text_span(content: "R", style: @tui.style(fg: :red, modifiers: [:underlined])),
|
|
155
|
+
@tui.text_span(content: "u", style: @tui.style(fg: :light_red, modifiers: [:bold])),
|
|
156
|
+
@tui.text_span(content: "b", style: @tui.style(fg: :red, modifiers: [:italic])),
|
|
157
|
+
@tui.text_span(content: "y", style: @tui.style(fg: :light_red, modifiers: [:reversed])),
|
|
158
|
+
])
|
|
159
|
+
|
|
160
|
+
# Create rich text for "Rust" - single styled Span
|
|
161
|
+
rust_span = @tui.text_span(
|
|
162
|
+
content: "Rust",
|
|
163
|
+
style: @tui.style(fg: :magenta, modifiers: [:bold, :underlined])
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
# Create ListItem for "Python" - demonstrates content + row background
|
|
167
|
+
python_item = @tui.list_item(
|
|
168
|
+
content: @tui.text_span(content: "Python", style: @tui.style(fg: :yellow)),
|
|
169
|
+
style: @tui.style(bg: :dark_gray)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# Create ListItem for "JavaScript" - demonstrates styled text with row background
|
|
173
|
+
javascript_item = @tui.list_item(
|
|
174
|
+
content: @tui.text_line(spans: [
|
|
175
|
+
@tui.text_span(content: "Java", style: @tui.style(fg: :yellow, modifiers: [:bold])),
|
|
176
|
+
@tui.text_span(content: "Script", style: @tui.style(fg: :light_yellow, modifiers: [:italic])),
|
|
177
|
+
]),
|
|
178
|
+
style: @tui.style(bg: :blue)
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
# Replace the styled placeholders
|
|
182
|
+
@item_sets[0][:items][0] = ruby_line
|
|
183
|
+
@item_sets[0][:items][1] = rust_span
|
|
184
|
+
@item_sets[0][:items][2] = python_item
|
|
185
|
+
@item_sets[0][:items][3] = javascript_item
|
|
186
|
+
|
|
217
187
|
# Initialize styles that require @tui
|
|
218
188
|
@highlight_styles = [
|
|
189
|
+
{ name: "Blue on White Bold", style: @tui.style(fg: :blue, bg: :white, modifiers: [:bold]) },
|
|
219
190
|
{ name: "Blue Bold", style: @tui.style(fg: :blue, modifiers: [:bold]) },
|
|
220
191
|
{ name: "Yellow on Black", style: @tui.style(fg: :yellow, bg: :black) },
|
|
221
192
|
{ name: "Green Italic", style: @tui.style(fg: :green, modifiers: [:italic]) },
|
|
@@ -245,7 +216,6 @@ class WidgetListDemo
|
|
|
245
216
|
# :nodoc:
|
|
246
217
|
private def render
|
|
247
218
|
items = @item_sets[@item_set_index][:items]
|
|
248
|
-
selection_label = @selected_index.nil? ? "none" : @selected_index.to_s
|
|
249
219
|
direction_config = @direction_configs[@direction_index]
|
|
250
220
|
spacing_config = @highlight_spacing_configs[@highlight_spacing_index]
|
|
251
221
|
repeat_config = @repeat_modes[@repeat_index]
|
|
@@ -253,6 +223,13 @@ class WidgetListDemo
|
|
|
253
223
|
highlight_symbol = @highlight_symbol_names[@highlight_symbol_index]
|
|
254
224
|
base_style_config = @base_styles[@base_style_index]
|
|
255
225
|
scroll_padding_config = @scroll_padding_configs[@scroll_padding_index]
|
|
226
|
+
offset_mode_config = @offset_modes[@offset_mode_index]
|
|
227
|
+
|
|
228
|
+
# Determine selection/offset based on mode
|
|
229
|
+
effective_selection = offset_mode_config[:allow_selection] ? @selected_index : nil
|
|
230
|
+
effective_offset = offset_mode_config[:offset]
|
|
231
|
+
selection_label = effective_selection.nil? ? "none" : effective_selection.to_s
|
|
232
|
+
offset_label = effective_offset.nil? ? "auto" : effective_offset.to_s
|
|
256
233
|
|
|
257
234
|
@tui.draw do |frame|
|
|
258
235
|
# Split into main content and control panel
|
|
@@ -261,7 +238,7 @@ class WidgetListDemo
|
|
|
261
238
|
direction: :vertical,
|
|
262
239
|
constraints: [
|
|
263
240
|
@tui.constraint_fill(1),
|
|
264
|
-
@tui.constraint_length(
|
|
241
|
+
@tui.constraint_length(8),
|
|
265
242
|
]
|
|
266
243
|
)
|
|
267
244
|
|
|
@@ -282,7 +259,8 @@ class WidgetListDemo
|
|
|
282
259
|
# Render list
|
|
283
260
|
list = @tui.list(
|
|
284
261
|
items:,
|
|
285
|
-
selected_index:
|
|
262
|
+
selected_index: effective_selection,
|
|
263
|
+
offset: effective_offset,
|
|
286
264
|
style: base_style_config[:style],
|
|
287
265
|
highlight_style: highlight_style_config[:style],
|
|
288
266
|
highlight_symbol:,
|
|
@@ -291,7 +269,7 @@ class WidgetListDemo
|
|
|
291
269
|
direction: direction_config[:direction],
|
|
292
270
|
scroll_padding: scroll_padding_config[:padding],
|
|
293
271
|
block: @tui.block(
|
|
294
|
-
title: "#{@item_sets[@item_set_index][:name]}
|
|
272
|
+
title: "#{@item_sets[@item_set_index][:name]} | Sel: #{selection_label} | Offset: #{offset_label}",
|
|
295
273
|
borders: [:all]
|
|
296
274
|
)
|
|
297
275
|
)
|
|
@@ -330,7 +308,11 @@ class WidgetListDemo
|
|
|
330
308
|
@tui.text_span(content: "b", style: @hotkey_style),
|
|
331
309
|
@tui.text_span(content: ": Base (#{base_style_config[:name]}) "),
|
|
332
310
|
@tui.text_span(content: "r", style: @hotkey_style),
|
|
333
|
-
@tui.text_span(content: ": Repeat (#{repeat_config[:name]})
|
|
311
|
+
@tui.text_span(content: ": Repeat (#{repeat_config[:name]})"),
|
|
312
|
+
]),
|
|
313
|
+
@tui.text_line(spans: [
|
|
314
|
+
@tui.text_span(content: "o", style: @hotkey_style),
|
|
315
|
+
@tui.text_span(content: ": Offset Mode (#{offset_mode_config[:name]}) "),
|
|
334
316
|
@tui.text_span(content: "q", style: @hotkey_style),
|
|
335
317
|
@tui.text_span(content: ": Quit"),
|
|
336
318
|
]),
|
|
@@ -373,6 +355,8 @@ class WidgetListDemo
|
|
|
373
355
|
@repeat_index = (@repeat_index + 1) % @repeat_modes.size
|
|
374
356
|
in type: :key, code: "p"
|
|
375
357
|
@scroll_padding_index = (@scroll_padding_index + 1) % @scroll_padding_configs.size
|
|
358
|
+
in type: :key, code: "o"
|
|
359
|
+
@offset_mode_index = (@offset_mode_index + 1) % @offset_modes.size
|
|
376
360
|
else
|
|
377
361
|
nil
|
|
378
362
|
end
|