ratatui_ruby 0.3.1 → 0.4.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 +14 -12
- data/.builds/ruby-3.3.yml +14 -12
- data/.builds/ruby-3.4.yml +14 -12
- data/.builds/ruby-4.0.0.yml +14 -12
- data/AGENTS.md +54 -13
- data/CHANGELOG.md +186 -1
- data/README.md +17 -15
- data/doc/application_architecture.md +116 -0
- data/doc/application_testing.md +12 -7
- data/doc/contributors/better_dx.md +543 -0
- data/doc/contributors/design/ruby_frontend.md +1 -1
- data/doc/contributors/developing_examples.md +203 -0
- data/doc/contributors/documentation_style.md +97 -0
- data/doc/contributors/dwim_dx.md +366 -0
- data/doc/contributors/example_analysis.md +82 -0
- data/doc/custom.css +14 -0
- data/doc/event_handling.md +119 -0
- data/doc/images/all_events.png +0 -0
- data/doc/images/analytics.png +0 -0
- data/doc/images/block_padding.png +0 -0
- data/doc/images/block_titles.png +0 -0
- data/doc/images/box_demo.png +0 -0
- data/doc/images/calendar_demo.png +0 -0
- data/doc/images/cell_demo.png +0 -0
- data/doc/images/chart_demo.png +0 -0
- data/doc/images/custom_widget.png +0 -0
- data/doc/images/flex_layout.png +0 -0
- data/doc/images/gauge_demo.png +0 -0
- data/doc/images/hit_test.png +0 -0
- data/doc/images/line_gauge_demo.png +0 -0
- data/doc/images/list_demo.png +0 -0
- data/doc/images/list_styles.png +0 -0
- data/doc/images/login_form.png +0 -0
- data/doc/images/map_demo.png +0 -0
- data/doc/images/mouse_events.png +0 -0
- data/doc/images/popup_demo.png +0 -0
- data/doc/images/quickstart_dsl.png +0 -0
- data/doc/images/quickstart_lifecycle.png +0 -0
- data/doc/images/ratatui_logo_demo.png +0 -0
- data/doc/images/readme_usage.png +0 -0
- data/doc/images/rich_text.png +0 -0
- data/doc/images/scroll_text.png +0 -0
- data/doc/images/scrollbar_demo.png +0 -0
- data/doc/images/sparkline_demo.png +0 -0
- data/doc/images/table_flex.png +0 -0
- data/doc/images/table_select.png +0 -0
- data/doc/images/widget_style_colors.png +0 -0
- data/doc/index.md +1 -0
- data/doc/interactive_design.md +121 -0
- data/doc/quickstart.md +147 -72
- data/examples/all_events/app.rb +169 -0
- data/examples/all_events/app.rbs +7 -0
- data/examples/all_events/test_app.rb +139 -0
- data/examples/analytics/app.rb +258 -0
- data/examples/analytics/app.rbs +7 -0
- data/examples/analytics/test_app.rb +132 -0
- data/examples/block_padding/app.rb +63 -0
- data/examples/block_padding/app.rbs +7 -0
- data/examples/block_padding/test_app.rb +31 -0
- data/examples/block_titles/app.rb +61 -0
- data/examples/block_titles/app.rbs +7 -0
- data/examples/block_titles/test_app.rb +34 -0
- data/examples/box_demo/app.rb +216 -0
- data/examples/box_demo/app.rbs +7 -0
- data/examples/box_demo/test_app.rb +88 -0
- data/examples/calendar_demo/app.rb +101 -0
- data/examples/calendar_demo/app.rbs +7 -0
- data/examples/calendar_demo/test_app.rb +108 -0
- data/examples/cell_demo/app.rb +108 -0
- data/examples/cell_demo/app.rbs +7 -0
- data/examples/cell_demo/test_app.rb +36 -0
- data/examples/chart_demo/app.rb +203 -0
- data/examples/chart_demo/app.rbs +7 -0
- data/examples/chart_demo/test_app.rb +102 -0
- data/examples/custom_widget/app.rb +51 -0
- data/examples/custom_widget/app.rbs +7 -0
- data/examples/custom_widget/test_app.rb +30 -0
- data/examples/flex_layout/app.rb +156 -0
- data/examples/flex_layout/app.rbs +7 -0
- data/examples/flex_layout/test_app.rb +65 -0
- data/examples/gauge_demo/app.rb +182 -0
- data/examples/gauge_demo/app.rbs +7 -0
- data/examples/gauge_demo/test_app.rb +120 -0
- data/examples/hit_test/app.rb +175 -0
- data/examples/hit_test/app.rbs +7 -0
- data/examples/hit_test/test_app.rb +102 -0
- data/examples/line_gauge_demo/app.rb +190 -0
- data/examples/line_gauge_demo/app.rbs +7 -0
- data/examples/line_gauge_demo/test_app.rb +129 -0
- data/examples/list_demo/app.rb +253 -0
- data/examples/list_demo/app.rbs +12 -0
- data/examples/list_demo/test_app.rb +237 -0
- data/examples/list_styles/app.rb +140 -0
- data/examples/list_styles/app.rbs +7 -0
- data/examples/list_styles/test_app.rb +157 -0
- data/examples/{login_form.rb → login_form/app.rb} +12 -16
- data/examples/login_form/app.rbs +7 -0
- data/examples/login_form/test_app.rb +51 -0
- data/examples/map_demo/app.rb +90 -0
- data/examples/map_demo/app.rbs +7 -0
- data/examples/map_demo/test_app.rb +149 -0
- data/examples/{mouse_events.rb → mouse_events/app.rb} +29 -27
- data/examples/mouse_events/app.rbs +7 -0
- data/examples/mouse_events/test_app.rb +53 -0
- data/examples/{popup_demo.rb → popup_demo/app.rb} +15 -17
- data/examples/popup_demo/app.rbs +7 -0
- data/examples/{test_popup_demo.rb → popup_demo/test_app.rb} +18 -26
- data/examples/quickstart_dsl/app.rb +36 -0
- data/examples/quickstart_dsl/app.rbs +7 -0
- data/examples/quickstart_dsl/test_app.rb +29 -0
- data/examples/quickstart_lifecycle/app.rb +39 -0
- data/examples/quickstart_lifecycle/app.rbs +7 -0
- data/examples/quickstart_lifecycle/test_app.rb +29 -0
- data/examples/ratatui_logo_demo/app.rb +79 -0
- data/examples/ratatui_logo_demo/app.rbs +7 -0
- data/examples/ratatui_logo_demo/test_app.rb +51 -0
- data/examples/ratatui_mascot_demo/app.rb +84 -0
- data/examples/ratatui_mascot_demo/app.rbs +7 -0
- data/examples/ratatui_mascot_demo/test_app.rb +47 -0
- data/examples/readme_usage/app.rb +29 -0
- data/examples/readme_usage/app.rbs +7 -0
- data/examples/readme_usage/test_app.rb +29 -0
- data/examples/rich_text/app.rb +141 -0
- data/examples/rich_text/app.rbs +7 -0
- data/examples/rich_text/test_app.rb +166 -0
- data/examples/scroll_text/app.rb +103 -0
- data/examples/scroll_text/app.rbs +7 -0
- data/examples/scroll_text/test_app.rb +110 -0
- data/examples/scrollbar_demo/app.rb +143 -0
- data/examples/scrollbar_demo/app.rbs +7 -0
- data/examples/scrollbar_demo/test_app.rb +77 -0
- data/examples/sparkline_demo/app.rb +240 -0
- data/examples/sparkline_demo/app.rbs +10 -0
- data/examples/sparkline_demo/test_app.rb +107 -0
- data/examples/table_flex/app.rb +65 -0
- data/examples/table_flex/app.rbs +7 -0
- data/examples/table_flex/test_app.rb +36 -0
- data/examples/table_select/app.rb +198 -0
- data/examples/table_select/app.rbs +7 -0
- data/examples/table_select/test_app.rb +180 -0
- data/examples/widget_style_colors/app.rb +104 -0
- data/examples/widget_style_colors/app.rbs +14 -0
- data/examples/widget_style_colors/test_app.rb +48 -0
- data/ext/ratatui_ruby/Cargo.lock +889 -115
- data/ext/ratatui_ruby/Cargo.toml +4 -3
- data/ext/ratatui_ruby/clippy.toml +7 -0
- data/ext/ratatui_ruby/extconf.rb +7 -0
- data/ext/ratatui_ruby/src/events.rs +218 -229
- data/ext/ratatui_ruby/src/lib.rs +38 -10
- data/ext/ratatui_ruby/src/rendering.rs +90 -10
- data/ext/ratatui_ruby/src/style.rs +281 -98
- data/ext/ratatui_ruby/src/terminal.rs +119 -25
- data/ext/ratatui_ruby/src/text.rs +171 -0
- data/ext/ratatui_ruby/src/widgets/barchart.rs +97 -24
- data/ext/ratatui_ruby/src/widgets/block.rs +31 -3
- data/ext/ratatui_ruby/src/widgets/calendar.rs +45 -44
- data/ext/ratatui_ruby/src/widgets/canvas.rs +46 -29
- data/ext/ratatui_ruby/src/widgets/chart.rs +69 -27
- data/ext/ratatui_ruby/src/widgets/clear.rs +3 -1
- data/ext/ratatui_ruby/src/widgets/gauge.rs +11 -4
- data/ext/ratatui_ruby/src/widgets/layout.rs +218 -15
- data/ext/ratatui_ruby/src/widgets/line_gauge.rs +92 -0
- data/ext/ratatui_ruby/src/widgets/list.rs +91 -11
- data/ext/ratatui_ruby/src/widgets/mod.rs +3 -0
- data/ext/ratatui_ruby/src/widgets/overlay.rs +3 -2
- data/ext/ratatui_ruby/src/widgets/paragraph.rs +35 -13
- data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +29 -0
- data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +44 -0
- data/ext/ratatui_ruby/src/widgets/scrollbar.rs +59 -7
- data/ext/ratatui_ruby/src/widgets/sparkline.rs +70 -6
- data/ext/ratatui_ruby/src/widgets/table.rs +173 -64
- data/ext/ratatui_ruby/src/widgets/tabs.rs +105 -5
- data/lib/ratatui_ruby/cell.rb +166 -0
- data/lib/ratatui_ruby/event/focus_gained.rb +49 -0
- data/lib/ratatui_ruby/event/focus_lost.rb +50 -0
- data/lib/ratatui_ruby/event/key.rb +211 -0
- data/lib/ratatui_ruby/event/mouse.rb +124 -0
- data/lib/ratatui_ruby/event/paste.rb +71 -0
- data/lib/ratatui_ruby/event/resize.rb +80 -0
- data/lib/ratatui_ruby/event.rb +79 -0
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +45 -0
- data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +27 -0
- data/lib/ratatui_ruby/schema/bar_chart.rb +228 -19
- data/lib/ratatui_ruby/schema/block.rb +186 -14
- data/lib/ratatui_ruby/schema/calendar.rb +74 -17
- data/lib/ratatui_ruby/schema/canvas.rb +215 -48
- data/lib/ratatui_ruby/schema/center.rb +49 -11
- data/lib/ratatui_ruby/schema/chart.rb +151 -41
- data/lib/ratatui_ruby/schema/clear.rb +41 -72
- data/lib/ratatui_ruby/schema/constraint.rb +82 -22
- data/lib/ratatui_ruby/schema/cursor.rb +27 -9
- data/lib/ratatui_ruby/schema/draw.rb +53 -0
- data/lib/ratatui_ruby/schema/gauge.rb +59 -15
- data/lib/ratatui_ruby/schema/layout.rb +95 -13
- data/lib/ratatui_ruby/schema/line_gauge.rb +78 -0
- data/lib/ratatui_ruby/schema/list.rb +93 -19
- data/lib/ratatui_ruby/schema/overlay.rb +34 -8
- data/lib/ratatui_ruby/schema/paragraph.rb +87 -30
- data/lib/ratatui_ruby/schema/ratatui_logo.rb +25 -0
- data/lib/ratatui_ruby/schema/ratatui_mascot.rb +29 -0
- data/lib/ratatui_ruby/schema/rect.rb +64 -15
- data/lib/ratatui_ruby/schema/scrollbar.rb +132 -24
- data/lib/ratatui_ruby/schema/shape/label.rb +66 -0
- data/lib/ratatui_ruby/schema/sparkline.rb +122 -15
- data/lib/ratatui_ruby/schema/style.rb +49 -21
- data/lib/ratatui_ruby/schema/table.rb +119 -21
- data/lib/ratatui_ruby/schema/tabs.rb +75 -13
- data/lib/ratatui_ruby/schema/text.rb +90 -0
- data/lib/ratatui_ruby/session.rb +146 -0
- data/lib/ratatui_ruby/test_helper.rb +156 -13
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby.rb +143 -23
- data/sig/ratatui_ruby/event.rbs +69 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +2 -1
- data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +16 -0
- data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +13 -0
- data/sig/ratatui_ruby/schema/bar_chart.rbs +20 -2
- data/sig/ratatui_ruby/schema/block.rbs +5 -4
- data/sig/ratatui_ruby/schema/calendar.rbs +6 -2
- data/sig/ratatui_ruby/schema/canvas.rbs +52 -39
- data/sig/ratatui_ruby/schema/center.rbs +3 -3
- data/sig/ratatui_ruby/schema/chart.rbs +8 -5
- data/sig/ratatui_ruby/schema/constraint.rbs +8 -5
- data/sig/ratatui_ruby/schema/cursor.rbs +1 -1
- data/sig/ratatui_ruby/schema/draw.rbs +23 -0
- data/sig/ratatui_ruby/schema/gauge.rbs +4 -2
- data/sig/ratatui_ruby/schema/layout.rbs +11 -1
- data/sig/ratatui_ruby/schema/line_gauge.rbs +16 -0
- data/sig/ratatui_ruby/schema/list.rbs +5 -1
- data/sig/ratatui_ruby/schema/paragraph.rbs +4 -1
- data/{lib/ratatui_ruby/output.rb → sig/ratatui_ruby/schema/ratatui_logo.rbs} +3 -2
- data/sig/ratatui_ruby/{buffer.rbs → schema/ratatui_mascot.rbs} +4 -3
- data/sig/ratatui_ruby/schema/rect.rbs +2 -1
- data/sig/ratatui_ruby/schema/scrollbar.rbs +18 -2
- data/sig/ratatui_ruby/schema/sparkline.rbs +6 -2
- data/sig/ratatui_ruby/schema/table.rbs +8 -1
- data/sig/ratatui_ruby/schema/tabs.rbs +5 -1
- data/sig/ratatui_ruby/schema/text.rbs +22 -0
- data/tasks/resources/build.yml.erb +13 -11
- data/tasks/terminal_preview/app_screenshot.rb +35 -0
- data/tasks/terminal_preview/crash_report.rb +54 -0
- data/tasks/terminal_preview/example_app.rb +25 -0
- data/tasks/terminal_preview/launcher_script.rb +48 -0
- data/tasks/terminal_preview/preview_collection.rb +60 -0
- data/tasks/terminal_preview/preview_timing.rb +22 -0
- data/tasks/terminal_preview/safety_confirmation.rb +58 -0
- data/tasks/terminal_preview/saved_screenshot.rb +55 -0
- data/tasks/terminal_preview/system_appearance.rb +11 -0
- data/tasks/terminal_preview/terminal_window.rb +138 -0
- data/tasks/terminal_preview/window_id.rb +14 -0
- data/tasks/terminal_preview.rake +28 -0
- data/tasks/test.rake +1 -1
- metadata +174 -53
- data/doc/images/examples-analytics.rb.png +0 -0
- data/doc/images/examples-box_demo.rb.png +0 -0
- data/doc/images/examples-calendar_demo.rb.png +0 -0
- data/doc/images/examples-chart_demo.rb.png +0 -0
- data/doc/images/examples-custom_widget.rb.png +0 -0
- data/doc/images/examples-dashboard.rb.png +0 -0
- data/doc/images/examples-list_styles.rb.png +0 -0
- data/doc/images/examples-login_form.rb.png +0 -0
- data/doc/images/examples-map_demo.rb.png +0 -0
- data/doc/images/examples-mouse_events.rb.png +0 -0
- data/doc/images/examples-popup_demo.rb.gif +0 -0
- data/doc/images/examples-quickstart_lifecycle.rb.png +0 -0
- data/doc/images/examples-scroll_text.rb.png +0 -0
- data/doc/images/examples-scrollbar_demo.rb.png +0 -0
- data/doc/images/examples-stock_ticker.rb.png +0 -0
- data/doc/images/examples-system_monitor.rb.png +0 -0
- data/doc/images/examples-table_select.rb.png +0 -0
- data/examples/analytics.rb +0 -88
- data/examples/box_demo.rb +0 -71
- data/examples/calendar_demo.rb +0 -55
- data/examples/chart_demo.rb +0 -84
- data/examples/custom_widget.rb +0 -43
- data/examples/dashboard.rb +0 -72
- data/examples/list_styles.rb +0 -66
- data/examples/map_demo.rb +0 -58
- data/examples/quickstart_dsl.rb +0 -30
- data/examples/quickstart_lifecycle.rb +0 -40
- data/examples/readme_usage.rb +0 -21
- data/examples/scroll_text.rb +0 -74
- data/examples/scrollbar_demo.rb +0 -75
- data/examples/stock_ticker.rb +0 -93
- data/examples/system_monitor.rb +0 -94
- data/examples/table_select.rb +0 -70
- data/examples/test_analytics.rb +0 -65
- data/examples/test_box_demo.rb +0 -38
- data/examples/test_calendar_demo.rb +0 -66
- data/examples/test_dashboard.rb +0 -38
- data/examples/test_list_styles.rb +0 -61
- data/examples/test_login_form.rb +0 -63
- data/examples/test_map_demo.rb +0 -100
- data/examples/test_scroll_text.rb +0 -130
- data/examples/test_stock_ticker.rb +0 -39
- data/examples/test_system_monitor.rb +0 -40
- data/examples/test_table_select.rb +0 -37
- data/ext/ratatui_ruby/src/buffer.rs +0 -54
- data/lib/ratatui_ruby/dsl.rb +0 -64
|
@@ -0,0 +1,124 @@
|
|
|
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
|
+
module RatatuiRuby
|
|
7
|
+
class Event
|
|
8
|
+
# Reports a mouse interaction.
|
|
9
|
+
#
|
|
10
|
+
# Modern terminals support rich pointer input, but the protocols are complex and varied.
|
|
11
|
+
# Handling clicks, drags, and scrolls requires robust parsing.
|
|
12
|
+
#
|
|
13
|
+
# This event simplifies the complexity. It tells you exactly *what* happened (+kind+),
|
|
14
|
+
# *where* it happened (+x+, +y+), and *which* button was involved.
|
|
15
|
+
#
|
|
16
|
+
# Use this to build interactive UIs. Implement click handlers, draggable sliders, or
|
|
17
|
+
# scrollable viewports with confidence.
|
|
18
|
+
#
|
|
19
|
+
# === Example
|
|
20
|
+
#
|
|
21
|
+
# if event.mouse? && event.down? && event.button == "left"
|
|
22
|
+
# puts "Left click at #{event.x}, #{event.y}"
|
|
23
|
+
# end
|
|
24
|
+
class Mouse < Event
|
|
25
|
+
# The kind of event (<tt>"down"</tt>, <tt>"up"</tt>, <tt>"drag"</tt>, <tt>"moved"</tt>, <tt>"scroll_up"</tt>, <tt>"scroll_down"</tt>).
|
|
26
|
+
#
|
|
27
|
+
# puts event.kind # => "down"
|
|
28
|
+
attr_reader :kind
|
|
29
|
+
# X coordinate (column).
|
|
30
|
+
#
|
|
31
|
+
# puts event.x # => 10
|
|
32
|
+
attr_reader :x
|
|
33
|
+
# Y coordinate (row).
|
|
34
|
+
#
|
|
35
|
+
# puts event.y # => 5
|
|
36
|
+
attr_reader :y
|
|
37
|
+
# The button pressed (<tt>"left"</tt>, <tt>"right"</tt>, <tt>"middle"</tt>, <tt>"none"</tt>).
|
|
38
|
+
#
|
|
39
|
+
# puts event.button # => "left"
|
|
40
|
+
#
|
|
41
|
+
# Can be <tt>nil</tt>, which is treated as <tt>"none"</tt>.
|
|
42
|
+
attr_reader :button
|
|
43
|
+
# List of active modifiers.
|
|
44
|
+
#
|
|
45
|
+
# puts event.modifiers # => ["ctrl"]
|
|
46
|
+
attr_reader :modifiers
|
|
47
|
+
|
|
48
|
+
# Returns true for Mouse events.
|
|
49
|
+
#
|
|
50
|
+
# event.mouse? # => true
|
|
51
|
+
# event.key? # => false
|
|
52
|
+
# event.resize? # => false
|
|
53
|
+
def mouse?
|
|
54
|
+
true
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Creates a new Mouse event.
|
|
58
|
+
#
|
|
59
|
+
# [kind]
|
|
60
|
+
# Event kind (String).
|
|
61
|
+
# [x]
|
|
62
|
+
# X coordinate (Integer).
|
|
63
|
+
# [y]
|
|
64
|
+
# Y coordinate (Integer).
|
|
65
|
+
# [button]
|
|
66
|
+
# Button name (String or <tt>nil</tt>).
|
|
67
|
+
# [modifiers]
|
|
68
|
+
# List of modifiers (Array<String>).
|
|
69
|
+
def initialize(kind:, x:, y:, button:, modifiers: [])
|
|
70
|
+
@kind = kind
|
|
71
|
+
@x = x
|
|
72
|
+
@y = y
|
|
73
|
+
@button = button || "none"
|
|
74
|
+
@modifiers = modifiers.sort
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Returns true if mouse button was pressed down.
|
|
78
|
+
def down?
|
|
79
|
+
@kind == "down"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Returns true if mouse button was released.
|
|
83
|
+
def up?
|
|
84
|
+
@kind == "up"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Returns true if mouse is being dragged.
|
|
88
|
+
def drag?
|
|
89
|
+
@kind == "drag"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Returns true if scroll wheel moved up.
|
|
93
|
+
def scroll_up?
|
|
94
|
+
@kind == "scroll_up"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Returns true if scroll wheel moved down.
|
|
98
|
+
#
|
|
99
|
+
# if event.scroll_down?
|
|
100
|
+
# scroll_offset += 1
|
|
101
|
+
# end
|
|
102
|
+
def scroll_down?
|
|
103
|
+
@kind == "scroll_down"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Deconstructs the event for pattern matching.
|
|
107
|
+
#
|
|
108
|
+
# case event
|
|
109
|
+
# in type: :mouse, kind: "down", x:, y:
|
|
110
|
+
# puts "Click at #{x}, #{y}"
|
|
111
|
+
# end
|
|
112
|
+
def deconstruct_keys(keys)
|
|
113
|
+
{ type: :mouse, kind: @kind, x: @x, y: @y, button: @button, modifiers: @modifiers }
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
##
|
|
117
|
+
# Compares this event with another for equality.
|
|
118
|
+
def ==(other)
|
|
119
|
+
return false unless other.is_a?(Mouse)
|
|
120
|
+
kind == other.kind && x == other.x && y == other.y && button == other.button && modifiers == other.modifiers
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
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
|
+
module RatatuiRuby
|
|
7
|
+
class Event
|
|
8
|
+
# Encapsulates pasted text.
|
|
9
|
+
#
|
|
10
|
+
# Users frequently paste text into terminals. Without specific handling, a paste appears as
|
|
11
|
+
# a flood of rapid keystrokes, often triggering accidental commands or confusing the input state.
|
|
12
|
+
#
|
|
13
|
+
# This event makes pasting safe. It groups the entire inserted block into a single atomic action.
|
|
14
|
+
#
|
|
15
|
+
# Handle this event to support bulk text insertion cleanly. Insert the +content+ directly into
|
|
16
|
+
# your field or buffer without triggering per-character logic.
|
|
17
|
+
#
|
|
18
|
+
# === Examples
|
|
19
|
+
#
|
|
20
|
+
# Using predicates:
|
|
21
|
+
# if event.paste?
|
|
22
|
+
# puts "Pasted: #{event.content}"
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# Using pattern matching:
|
|
26
|
+
# case event
|
|
27
|
+
# in type: :paste, content:
|
|
28
|
+
# puts "Pasted: #{content}"
|
|
29
|
+
# end
|
|
30
|
+
class Paste < Event
|
|
31
|
+
# The pasted content.
|
|
32
|
+
#
|
|
33
|
+
# puts event.content # => "https://example.com"
|
|
34
|
+
attr_reader :content
|
|
35
|
+
|
|
36
|
+
# Returns true for Paste events.
|
|
37
|
+
#
|
|
38
|
+
# event.paste? # => true
|
|
39
|
+
# event.key? # => false
|
|
40
|
+
# event.resize? # => false
|
|
41
|
+
def paste?
|
|
42
|
+
true
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Creates a new Paste event.
|
|
46
|
+
#
|
|
47
|
+
# [content]
|
|
48
|
+
# Pasted text (String).
|
|
49
|
+
def initialize(content:)
|
|
50
|
+
@content = content
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Deconstructs the event for pattern matching.
|
|
54
|
+
#
|
|
55
|
+
# case event
|
|
56
|
+
# in type: :paste, content:
|
|
57
|
+
# puts "User pasted: #{content}"
|
|
58
|
+
# end
|
|
59
|
+
def deconstruct_keys(keys)
|
|
60
|
+
{ type: :paste, content: @content }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
##
|
|
64
|
+
# Compares this event with another for equality.
|
|
65
|
+
def ==(other)
|
|
66
|
+
return false unless other.is_a?(Paste)
|
|
67
|
+
content == other.content
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
module RatatuiRuby
|
|
7
|
+
class Event
|
|
8
|
+
# Signals a change in terminal dimensions.
|
|
9
|
+
#
|
|
10
|
+
# The terminal window is dynamic, not static. The user changes its dimensions at will,
|
|
11
|
+
# usually breaking a fixed layout.
|
|
12
|
+
#
|
|
13
|
+
# This event captures the new state. It delivers the updated +width+ and +height+
|
|
14
|
+
# immediately after the change.
|
|
15
|
+
#
|
|
16
|
+
# Use these dimensions to drive your layout logic. Recalculate constraints. Reallocate space.
|
|
17
|
+
# Fill the new canvas completely to maintain a responsive design.
|
|
18
|
+
#
|
|
19
|
+
# === Examples
|
|
20
|
+
#
|
|
21
|
+
# Using predicates:
|
|
22
|
+
# if event.resize?
|
|
23
|
+
# puts "Resized to #{event.width}x#{event.height}"
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# Using pattern matching:
|
|
27
|
+
# case event
|
|
28
|
+
# in type: :resize, width:, height:
|
|
29
|
+
# puts "Resized to #{width}x#{height}"
|
|
30
|
+
# end
|
|
31
|
+
class Resize < Event
|
|
32
|
+
# New terminal width in columns.
|
|
33
|
+
#
|
|
34
|
+
# puts event.width # => 80
|
|
35
|
+
attr_reader :width
|
|
36
|
+
|
|
37
|
+
# New terminal height in rows.
|
|
38
|
+
#
|
|
39
|
+
# puts event.height # => 24
|
|
40
|
+
attr_reader :height
|
|
41
|
+
|
|
42
|
+
# Returns true for Resize events.
|
|
43
|
+
#
|
|
44
|
+
# event.resize? # => true
|
|
45
|
+
# event.key? # => false
|
|
46
|
+
# event.mouse? # => false
|
|
47
|
+
def resize?
|
|
48
|
+
true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Creates a new Resize event.
|
|
52
|
+
#
|
|
53
|
+
# [width]
|
|
54
|
+
# New width (Integer).
|
|
55
|
+
# [height]
|
|
56
|
+
# New height (Integer).
|
|
57
|
+
def initialize(width:, height:)
|
|
58
|
+
@width = width
|
|
59
|
+
@height = height
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Deconstructs the event for pattern matching.
|
|
63
|
+
#
|
|
64
|
+
# case event
|
|
65
|
+
# in type: :resize, width:, height:
|
|
66
|
+
# puts "Resized to #{width}x#{height}"
|
|
67
|
+
# end
|
|
68
|
+
def deconstruct_keys(keys)
|
|
69
|
+
{ type: :resize, width: @width, height: @height }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Compares this event with another for equality.
|
|
74
|
+
def ==(other)
|
|
75
|
+
return false unless other.is_a?(Resize)
|
|
76
|
+
width == other.width && height == other.height
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
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
|
+
module RatatuiRuby
|
|
7
|
+
# Base class for all RatatuiRuby events.
|
|
8
|
+
#
|
|
9
|
+
# Events are returned by RatatuiRuby.poll_event.
|
|
10
|
+
# All events support Ruby 3.0+ pattern matching via #deconstruct_keys.
|
|
11
|
+
#
|
|
12
|
+
# See RatatuiRuby.poll_event
|
|
13
|
+
class Event
|
|
14
|
+
# Returns true if this is a Key event.
|
|
15
|
+
def key?
|
|
16
|
+
false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Returns true if this is a Mouse event.
|
|
20
|
+
def mouse?
|
|
21
|
+
false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Returns true if this is a Resize event.
|
|
25
|
+
def resize?
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Returns true if this is a Paste event.
|
|
30
|
+
def paste?
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Returns true if this is a FocusGained event.
|
|
35
|
+
def focus_gained?
|
|
36
|
+
false
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Returns true if this is a FocusLost event.
|
|
40
|
+
def focus_lost?
|
|
41
|
+
false
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Responds to dynamic predicate methods for key checks.
|
|
45
|
+
# All non-Key events return false for any key predicate.
|
|
46
|
+
def method_missing(name, *args, &block)
|
|
47
|
+
if name.to_s.end_with?("?")
|
|
48
|
+
false
|
|
49
|
+
else
|
|
50
|
+
super
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Declares that this class responds to dynamic predicate methods.
|
|
55
|
+
def respond_to_missing?(name, *args)
|
|
56
|
+
name.to_s.end_with?("?") || super
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Deconstructs the event for pattern matching.
|
|
60
|
+
#
|
|
61
|
+
# Keys argument is unused but required by the protocol.
|
|
62
|
+
#
|
|
63
|
+
# case event
|
|
64
|
+
# in type: :key, code:
|
|
65
|
+
# puts "Key: #{code}"
|
|
66
|
+
# end
|
|
67
|
+
def deconstruct_keys(keys)
|
|
68
|
+
{}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
require_relative "event/key"
|
|
75
|
+
require_relative "event/mouse"
|
|
76
|
+
require_relative "event/resize"
|
|
77
|
+
require_relative "event/paste"
|
|
78
|
+
require_relative "event/focus_gained"
|
|
79
|
+
require_relative "event/focus_lost"
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
module RatatuiRuby
|
|
7
|
+
class BarChart
|
|
8
|
+
# A bar in a grouped bar chart.
|
|
9
|
+
#
|
|
10
|
+
# === Examples
|
|
11
|
+
#
|
|
12
|
+
# BarChart::Bar.new(value: 10, style: Style.new(fg: :red), label: "A")
|
|
13
|
+
class Bar < Data.define(:value, :label, :style, :value_style, :text_value)
|
|
14
|
+
##
|
|
15
|
+
# :attr_reader: value
|
|
16
|
+
# The value of the bar (Integer).
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# :attr_reader: label
|
|
20
|
+
# The label of the bar (optional String).
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# :attr_reader: style
|
|
24
|
+
# The style of the bar (optional Style).
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# :attr_reader: value_style
|
|
28
|
+
# The style of the value (optional Style).
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
# :attr_reader: text_value
|
|
32
|
+
# The text to display as the value (optional String).
|
|
33
|
+
|
|
34
|
+
def initialize(value:, label: nil, style: nil, value_style: nil, text_value: nil)
|
|
35
|
+
super(
|
|
36
|
+
value: Integer(value),
|
|
37
|
+
label: label,
|
|
38
|
+
style: style,
|
|
39
|
+
value_style: value_style,
|
|
40
|
+
text_value: text_value
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
module RatatuiRuby
|
|
7
|
+
class BarChart
|
|
8
|
+
# A group of bars in a grouped bar chart.
|
|
9
|
+
#
|
|
10
|
+
# === Examples
|
|
11
|
+
#
|
|
12
|
+
# BarChart::BarGroup.new(label: "Q1", bars: [BarChart::Bar.new(value: 10), BarChart::Bar.new(value: 20)])
|
|
13
|
+
class BarGroup < Data.define(:label, :bars)
|
|
14
|
+
##
|
|
15
|
+
# :attr_reader: label
|
|
16
|
+
# The label of the group (String).
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# :attr_reader: bars
|
|
20
|
+
# The bars in the group (Array of Bar).
|
|
21
|
+
|
|
22
|
+
def initialize(label:, bars:)
|
|
23
|
+
super
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -4,25 +4,234 @@
|
|
|
4
4
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
5
|
|
|
6
6
|
module RatatuiRuby
|
|
7
|
-
|
|
8
|
-
#
|
|
9
|
-
# [data] A hash of { "Label" => value (Integer) }.
|
|
10
|
-
# [bar_width] The width of each bar in the chart.
|
|
11
|
-
# [bar_gap] The gap between bars.
|
|
12
|
-
# [max] Optional maximum value for the Y-axis.
|
|
13
|
-
# [style] Optional style for the bars.
|
|
14
|
-
# [block] Optional block widget to wrap the chart.
|
|
15
|
-
class BarChart < Data.define(:data, :bar_width, :bar_gap, :max, :style, :block)
|
|
16
|
-
# Creates a new BarChart widget.
|
|
7
|
+
# Displays categorical data as bars.
|
|
17
8
|
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
|
|
25
|
-
|
|
9
|
+
# Raw tables of numbers are hard to scan. Comparing magnitudes requires mental arithmetic, which slows down decision-making.
|
|
10
|
+
#
|
|
11
|
+
# This widget visualizes the data. It renders vertical bars proportional to their value.
|
|
12
|
+
#
|
|
13
|
+
# Use it to compare server loads, sales figures, or any discrete datasets.
|
|
14
|
+
#
|
|
15
|
+
# === Examples
|
|
16
|
+
#
|
|
17
|
+
# BarChart.new(
|
|
18
|
+
# data: { "US" => 40, "EU" => 35, "AP" => 25 },
|
|
19
|
+
# bar_width: 5,
|
|
20
|
+
# style: Style.new(fg: :green)
|
|
21
|
+
# )
|
|
22
|
+
#
|
|
23
|
+
# # Grouped Bar Chart
|
|
24
|
+
# BarChart.new(
|
|
25
|
+
# data: [
|
|
26
|
+
# BarGroup.new(label: "Q1", bars: [Bar.new(value: 40), Bar.new(value: 45)]),
|
|
27
|
+
# BarGroup.new(label: "Q2", bars: [Bar.new(value: 50), Bar.new(value: 55)])
|
|
28
|
+
# ],
|
|
29
|
+
# bar_width: 5,
|
|
30
|
+
# group_gap: 3
|
|
31
|
+
# )
|
|
32
|
+
class BarChart < Data.define(:data, :bar_width, :bar_gap, :group_gap, :max, :style, :block, :direction, :label_style, :value_style, :bar_set)
|
|
33
|
+
##
|
|
34
|
+
##
|
|
35
|
+
##
|
|
36
|
+
##
|
|
37
|
+
# :attr_reader: data
|
|
38
|
+
# The data to display.
|
|
39
|
+
#
|
|
40
|
+
# Supports multiple formats:
|
|
41
|
+
# [<tt>Hash</tt>]
|
|
42
|
+
# Mapping labels (<tt>String</tt> or <tt>Symbol</tt>) to values (<tt>Integer</tt>).
|
|
43
|
+
# [<tt>Array</tt> of tuples]
|
|
44
|
+
# Ordered list of <tt>["Label", Value]</tt> or <tt>["Label", Value, Style]</tt> pairs.
|
|
45
|
+
# [<tt>Array</tt> of <tt>BarChart::BarGroup</tt>]
|
|
46
|
+
# List of <tt>BarChart::BarGroup</tt> objects for grouped charts.
|
|
47
|
+
#
|
|
48
|
+
# === Examples
|
|
49
|
+
#
|
|
50
|
+
# Hash (Simple):
|
|
51
|
+
# { "Apples" => 10, :Oranges => 15 }
|
|
52
|
+
#
|
|
53
|
+
# Array of Tuples (Ordered):
|
|
54
|
+
# [["Mon", 20], ["Tue", 30], ["Wed", 25]]
|
|
55
|
+
#
|
|
56
|
+
# BarGroup (Grouped):
|
|
57
|
+
# [
|
|
58
|
+
# RatatuiRuby::BarChart::BarGroup.new(label: "Q1", bars: [
|
|
59
|
+
# RatatuiRuby::BarChart::Bar.new(value: 50, label: "Rev"),
|
|
60
|
+
# RatatuiRuby::BarChart::Bar.new(value: 30, label: "Cost")
|
|
61
|
+
# ])
|
|
62
|
+
# ]
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
# :attr_reader: bar_width
|
|
66
|
+
# Width of each bar in characters.
|
|
67
|
+
|
|
68
|
+
##
|
|
69
|
+
# :attr_reader: bar_gap
|
|
70
|
+
# Spaces between bars.
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# :attr_reader: group_gap
|
|
74
|
+
# Spaces between groups (for grouped bar charts).
|
|
75
|
+
|
|
76
|
+
##
|
|
77
|
+
# :attr_reader: max
|
|
78
|
+
# Maximum value for the Y-axis (optional).
|
|
79
|
+
#
|
|
80
|
+
# If nil, it is calculated from the data.
|
|
81
|
+
|
|
82
|
+
##
|
|
83
|
+
# :attr_reader: style
|
|
84
|
+
# Style for the bars.
|
|
85
|
+
|
|
86
|
+
##
|
|
87
|
+
# :attr_reader: block
|
|
88
|
+
# Optional wrapping block.
|
|
89
|
+
|
|
90
|
+
##
|
|
91
|
+
# :attr_reader: label_style
|
|
92
|
+
# Style for the bar labels (optional).
|
|
93
|
+
|
|
94
|
+
##
|
|
95
|
+
# :attr_reader: value_style
|
|
96
|
+
# Style for the bar values (optional).
|
|
97
|
+
|
|
98
|
+
##
|
|
99
|
+
# :attr_reader: bar_set
|
|
100
|
+
# Custom characters for the bars (optional).
|
|
101
|
+
#
|
|
102
|
+
# A Hash with keys defining the characters for the bars.
|
|
103
|
+
# Keys: <tt>:empty</tt>, <tt>:one_eighth</tt>, <tt>:one_quarter</tt>, <tt>:three_eighths</tt>, <tt>:half</tt>, <tt>:five_eighths</tt>, <tt>:three_quarters</tt>, <tt>:seven_eighths</tt>, <tt>:full</tt>.
|
|
104
|
+
#
|
|
105
|
+
# You can also use integers (0-8) as keys, where 0 is empty, 4 is half, and 8 is full.
|
|
106
|
+
#
|
|
107
|
+
# Alternatively, you can pass an Array of 9 strings, where index 0 is empty and index 8 is full.
|
|
108
|
+
#
|
|
109
|
+
# === Examples
|
|
110
|
+
#
|
|
111
|
+
# bar_set: {
|
|
112
|
+
# empty: " ",
|
|
113
|
+
# one_eighth: " ",
|
|
114
|
+
# one_quarter: "▂",
|
|
115
|
+
# three_eighths: "▃",
|
|
116
|
+
# half: "▄",
|
|
117
|
+
# five_eighths: "▅",
|
|
118
|
+
# three_quarters: "▆",
|
|
119
|
+
# seven_eighths: "▇",
|
|
120
|
+
# full: "█"
|
|
121
|
+
# }
|
|
122
|
+
#
|
|
123
|
+
# # Numeric keys (0-8)
|
|
124
|
+
# bar_set: {
|
|
125
|
+
# 0 => " ", 1 => " ", 2 => "▂", 3 => "▃", 4 => "▄", 5 => "▅", 6 => "▆", 7 => "▇", 8 => "█"
|
|
126
|
+
# }
|
|
127
|
+
#
|
|
128
|
+
# # Array (9 items)
|
|
129
|
+
# bar_set: [" ", " ", "▂", "▃", "▄", "▅", "▆", "▇", "█"]
|
|
130
|
+
|
|
131
|
+
BAR_KEYS = %i[empty one_eighth one_quarter three_eighths half five_eighths three_quarters seven_eighths full].freeze
|
|
132
|
+
|
|
133
|
+
# Creates a new BarChart widget.
|
|
134
|
+
#
|
|
135
|
+
# [data]
|
|
136
|
+
# Data to display. Hash, Array of arrays, or Array of BarGroup.
|
|
137
|
+
# [bar_width]
|
|
138
|
+
# Width of each bar (Integer).
|
|
139
|
+
# [bar_gap]
|
|
140
|
+
# Gap between bars (Integer).
|
|
141
|
+
# [group_gap]
|
|
142
|
+
# Gap between groups (Integer).
|
|
143
|
+
# [max]
|
|
144
|
+
# Maximum value of the bar chart (Integer).
|
|
145
|
+
# [style]
|
|
146
|
+
# Base style for the widget (Style).
|
|
147
|
+
# [block]
|
|
148
|
+
# Block to render around the chart (Block).
|
|
149
|
+
# [direction]
|
|
150
|
+
# Direction of the bars (:vertical or :horizontal).
|
|
151
|
+
# [label_style]
|
|
152
|
+
# Style object for labels (optional).
|
|
153
|
+
# [value_style]
|
|
154
|
+
# Style object for values (optional).
|
|
155
|
+
# [bar_set]
|
|
156
|
+
# Hash or Array: Custom characters for the bars.
|
|
157
|
+
def initialize(data:, bar_width: 3, bar_gap: 1, group_gap: 0, max: nil, style: nil, block: nil, direction: :vertical, label_style: nil, value_style: nil, bar_set: nil)
|
|
158
|
+
if bar_set
|
|
159
|
+
if bar_set.is_a?(Array) && bar_set.size == 9
|
|
160
|
+
# Convert Array to Hash using BAR_KEYS order
|
|
161
|
+
bar_set = BAR_KEYS.zip(bar_set).to_h
|
|
162
|
+
else
|
|
163
|
+
bar_set = bar_set.dup
|
|
164
|
+
# Normalize numeric keys (0-8) to symbolic keys
|
|
165
|
+
BAR_KEYS.each_with_index do |key, i|
|
|
166
|
+
if val = bar_set.delete(i) || bar_set.delete(i.to_s)
|
|
167
|
+
bar_set[key] = val
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Normalize data to Array of BarGroup
|
|
174
|
+
data = if data.is_a?(Hash)
|
|
175
|
+
if direction == :horizontal
|
|
176
|
+
bars = data.map do |label, value|
|
|
177
|
+
Bar.new(value: value, label: label.to_s)
|
|
178
|
+
end
|
|
179
|
+
[BarGroup.new(label: "", bars: bars)]
|
|
180
|
+
else
|
|
181
|
+
data.map do |label, value|
|
|
182
|
+
BarGroup.new(label: label.to_s, bars: [Bar.new(value: value)])
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
elsif data.is_a?(Array)
|
|
186
|
+
if data.empty?
|
|
187
|
+
[]
|
|
188
|
+
elsif data.first.is_a?(BarGroup)
|
|
189
|
+
data
|
|
190
|
+
elsif data.first.is_a?(Array)
|
|
191
|
+
# Tuples
|
|
192
|
+
if direction == :horizontal
|
|
193
|
+
bars = data.map do |item|
|
|
194
|
+
label = item[0].to_s
|
|
195
|
+
value = item[1]
|
|
196
|
+
style = item[2]
|
|
197
|
+
|
|
198
|
+
bar = Bar.new(value: value, label: label)
|
|
199
|
+
bar = bar.with(style: style) if style
|
|
200
|
+
bar
|
|
201
|
+
end
|
|
202
|
+
[BarGroup.new(label: "", bars: bars)]
|
|
203
|
+
else
|
|
204
|
+
data.map do |item|
|
|
205
|
+
label = item[0].to_s
|
|
206
|
+
value = item[1]
|
|
207
|
+
style = item[2]
|
|
208
|
+
|
|
209
|
+
bar = Bar.new(value: value)
|
|
210
|
+
bar = bar.with(style: style) if style
|
|
211
|
+
BarGroup.new(label: label, bars: [bar])
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
else
|
|
215
|
+
# Fallback
|
|
216
|
+
data
|
|
217
|
+
end
|
|
218
|
+
else
|
|
219
|
+
data
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
super(
|
|
223
|
+
data: data,
|
|
224
|
+
bar_width: Integer(bar_width),
|
|
225
|
+
bar_gap: Integer(bar_gap),
|
|
226
|
+
group_gap: Integer(group_gap),
|
|
227
|
+
max: max.nil? ? nil : Integer(max),
|
|
228
|
+
style: style,
|
|
229
|
+
block: block,
|
|
230
|
+
direction: direction,
|
|
231
|
+
label_style: label_style,
|
|
232
|
+
value_style: value_style,
|
|
233
|
+
bar_set: bar_set
|
|
234
|
+
)
|
|
235
|
+
end
|
|
26
236
|
end
|
|
27
|
-
end
|
|
28
237
|
end
|