ratatui_ruby 1.4.0-x86_64-linux
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 +7 -0
- data/LICENSE +15 -0
- data/LICENSES/AGPL-3.0-or-later.txt +661 -0
- data/LICENSES/CC-BY-SA-4.0.txt +427 -0
- data/LICENSES/CC0-1.0.txt +121 -0
- data/LICENSES/LGPL-3.0-or-later.txt +304 -0
- data/LICENSES/MIT-0.txt +16 -0
- data/LICENSES/MIT.txt +21 -0
- data/REUSE.toml +42 -0
- data/exe/.gitkeep +0 -0
- data/ext/ratatui_ruby/.cargo/config.toml +13 -0
- data/ext/ratatui_ruby/.gitignore +4 -0
- data/ext/ratatui_ruby/Cargo.lock +1737 -0
- data/ext/ratatui_ruby/Cargo.toml +24 -0
- data/ext/ratatui_ruby/clippy.toml +7 -0
- data/ext/ratatui_ruby/extconf.rb +21 -0
- data/ext/ratatui_ruby/src/color.rs +82 -0
- data/ext/ratatui_ruby/src/errors.rs +28 -0
- data/ext/ratatui_ruby/src/events.rs +700 -0
- data/ext/ratatui_ruby/src/frame.rs +241 -0
- data/ext/ratatui_ruby/src/lib.rs +343 -0
- data/ext/ratatui_ruby/src/lib_header.rs +11 -0
- data/ext/ratatui_ruby/src/rendering.rs +158 -0
- data/ext/ratatui_ruby/src/string_width.rs +101 -0
- data/ext/ratatui_ruby/src/style.rs +469 -0
- data/ext/ratatui_ruby/src/terminal/capabilities.rs +46 -0
- data/ext/ratatui_ruby/src/terminal/init.rs +233 -0
- data/ext/ratatui_ruby/src/terminal/mod.rs +42 -0
- data/ext/ratatui_ruby/src/terminal/mutations.rs +158 -0
- data/ext/ratatui_ruby/src/terminal/queries.rs +231 -0
- data/ext/ratatui_ruby/src/terminal/query.rs +400 -0
- data/ext/ratatui_ruby/src/terminal/storage.rs +109 -0
- data/ext/ratatui_ruby/src/terminal/wrapper.rs +16 -0
- data/ext/ratatui_ruby/src/text.rs +225 -0
- data/ext/ratatui_ruby/src/widgets/barchart.rs +169 -0
- data/ext/ratatui_ruby/src/widgets/block.rs +41 -0
- data/ext/ratatui_ruby/src/widgets/calendar.rs +84 -0
- data/ext/ratatui_ruby/src/widgets/canvas.rs +183 -0
- data/ext/ratatui_ruby/src/widgets/center.rs +79 -0
- data/ext/ratatui_ruby/src/widgets/chart.rs +222 -0
- data/ext/ratatui_ruby/src/widgets/clear.rs +39 -0
- data/ext/ratatui_ruby/src/widgets/cursor.rs +32 -0
- data/ext/ratatui_ruby/src/widgets/gauge.rs +65 -0
- data/ext/ratatui_ruby/src/widgets/layout.rs +379 -0
- data/ext/ratatui_ruby/src/widgets/line_gauge.rs +100 -0
- data/ext/ratatui_ruby/src/widgets/list.rs +378 -0
- data/ext/ratatui_ruby/src/widgets/list_state.rs +173 -0
- data/ext/ratatui_ruby/src/widgets/mod.rs +26 -0
- data/ext/ratatui_ruby/src/widgets/overlay.rs +24 -0
- data/ext/ratatui_ruby/src/widgets/paragraph.rs +87 -0
- data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +40 -0
- data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +55 -0
- data/ext/ratatui_ruby/src/widgets/scrollbar.rs +214 -0
- data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
- data/ext/ratatui_ruby/src/widgets/sparkline.rs +127 -0
- data/ext/ratatui_ruby/src/widgets/table.rs +415 -0
- data/ext/ratatui_ruby/src/widgets/table_state.rs +203 -0
- data/ext/ratatui_ruby/src/widgets/tabs.rs +194 -0
- data/lib/ratatui_ruby/backend/window_size.rb +50 -0
- data/lib/ratatui_ruby/backend.rb +59 -0
- data/lib/ratatui_ruby/buffer/cell.rb +212 -0
- data/lib/ratatui_ruby/buffer.rb +149 -0
- data/lib/ratatui_ruby/cell.rb +208 -0
- data/lib/ratatui_ruby/debug.rb +215 -0
- data/lib/ratatui_ruby/draw.rb +63 -0
- data/lib/ratatui_ruby/event/focus_gained.rb +125 -0
- data/lib/ratatui_ruby/event/focus_lost.rb +127 -0
- data/lib/ratatui_ruby/event/key/character.rb +53 -0
- data/lib/ratatui_ruby/event/key/dwim.rb +301 -0
- data/lib/ratatui_ruby/event/key/media.rb +46 -0
- data/lib/ratatui_ruby/event/key/modifier.rb +107 -0
- data/lib/ratatui_ruby/event/key/navigation.rb +72 -0
- data/lib/ratatui_ruby/event/key/system.rb +47 -0
- data/lib/ratatui_ruby/event/key.rb +479 -0
- data/lib/ratatui_ruby/event/mouse.rb +291 -0
- data/lib/ratatui_ruby/event/none.rb +53 -0
- data/lib/ratatui_ruby/event/paste.rb +130 -0
- data/lib/ratatui_ruby/event/resize.rb +221 -0
- data/lib/ratatui_ruby/event/sync.rb +52 -0
- data/lib/ratatui_ruby/event.rb +163 -0
- data/lib/ratatui_ruby/frame.rb +257 -0
- data/lib/ratatui_ruby/labs/a11y.rb +182 -0
- data/lib/ratatui_ruby/labs/frame_a11y_capture.rb +50 -0
- data/lib/ratatui_ruby/labs.rb +47 -0
- data/lib/ratatui_ruby/layout/alignment.rb +91 -0
- data/lib/ratatui_ruby/layout/constraint.rb +337 -0
- data/lib/ratatui_ruby/layout/layout.rb +258 -0
- data/lib/ratatui_ruby/layout/position.rb +81 -0
- data/lib/ratatui_ruby/layout/rect.rb +733 -0
- data/lib/ratatui_ruby/layout/size.rb +62 -0
- data/lib/ratatui_ruby/layout.rb +29 -0
- data/lib/ratatui_ruby/list_state.rb +201 -0
- data/lib/ratatui_ruby/output_guard.rb +171 -0
- data/lib/ratatui_ruby/ratatui_ruby.so +0 -0
- data/lib/ratatui_ruby/scrollbar_state.rb +122 -0
- data/lib/ratatui_ruby/style/color.rb +149 -0
- data/lib/ratatui_ruby/style/style.rb +147 -0
- data/lib/ratatui_ruby/style.rb +19 -0
- data/lib/ratatui_ruby/symbols.rb +435 -0
- data/lib/ratatui_ruby/synthetic_events.rb +106 -0
- data/lib/ratatui_ruby/table_state.rb +251 -0
- data/lib/ratatui_ruby/terminal/capabilities.rb +316 -0
- data/lib/ratatui_ruby/terminal/viewport.rb +80 -0
- data/lib/ratatui_ruby/terminal.rb +66 -0
- data/lib/ratatui_ruby/terminal_lifecycle.rb +303 -0
- data/lib/ratatui_ruby/terminal_lifecycle.rb.bak +197 -0
- data/lib/ratatui_ruby/test_helper/event_injection.rb +241 -0
- data/lib/ratatui_ruby/test_helper/global_state.rb +111 -0
- data/lib/ratatui_ruby/test_helper/snapshot.rb +568 -0
- data/lib/ratatui_ruby/test_helper/snapshots/axis_labels_alignment.ansi +24 -0
- data/lib/ratatui_ruby/test_helper/snapshots/axis_labels_alignment.txt +24 -0
- data/lib/ratatui_ruby/test_helper/snapshots/barchart_styled_label.ansi +5 -0
- data/lib/ratatui_ruby/test_helper/snapshots/barchart_styled_label.txt +5 -0
- data/lib/ratatui_ruby/test_helper/snapshots/chart_rendering.ansi +24 -0
- data/lib/ratatui_ruby/test_helper/snapshots/chart_rendering.txt +24 -0
- data/lib/ratatui_ruby/test_helper/snapshots/half_block_marker.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/half_block_marker.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_bottom.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_bottom.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_left.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_left.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_right.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_right.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_top.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_top.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/my_snapshot.txt +1 -0
- data/lib/ratatui_ruby/test_helper/snapshots/styled_axis_title.ansi +10 -0
- data/lib/ratatui_ruby/test_helper/snapshots/styled_axis_title.txt +10 -0
- data/lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.ansi +10 -0
- data/lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.txt +10 -0
- data/lib/ratatui_ruby/test_helper/style_assertions.rb +449 -0
- data/lib/ratatui_ruby/test_helper/subprocess_timeout.rb +35 -0
- data/lib/ratatui_ruby/test_helper/terminal.rb +187 -0
- data/lib/ratatui_ruby/test_helper/test_doubles.rb +86 -0
- data/lib/ratatui_ruby/test_helper.rb +115 -0
- data/lib/ratatui_ruby/text/line.rb +245 -0
- data/lib/ratatui_ruby/text/span.rb +158 -0
- data/lib/ratatui_ruby/text.rb +99 -0
- data/lib/ratatui_ruby/tui/buffer_factories.rb +22 -0
- data/lib/ratatui_ruby/tui/canvas_factories.rb +149 -0
- data/lib/ratatui_ruby/tui/core.rb +67 -0
- data/lib/ratatui_ruby/tui/layout_factories.rb +153 -0
- data/lib/ratatui_ruby/tui/state_factories.rb +77 -0
- data/lib/ratatui_ruby/tui/style_factories.rb +22 -0
- data/lib/ratatui_ruby/tui/text_factories.rb +86 -0
- data/lib/ratatui_ruby/tui/widget_factories.rb +272 -0
- data/lib/ratatui_ruby/tui.rb +106 -0
- data/lib/ratatui_ruby/version.rb +12 -0
- data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +51 -0
- data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +29 -0
- data/lib/ratatui_ruby/widgets/bar_chart.rb +308 -0
- data/lib/ratatui_ruby/widgets/block.rb +266 -0
- data/lib/ratatui_ruby/widgets/calendar.rb +88 -0
- data/lib/ratatui_ruby/widgets/canvas.rb +297 -0
- data/lib/ratatui_ruby/widgets/cell.rb +59 -0
- data/lib/ratatui_ruby/widgets/center.rb +71 -0
- data/lib/ratatui_ruby/widgets/chart.rb +172 -0
- data/lib/ratatui_ruby/widgets/clear.rb +66 -0
- data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
- data/lib/ratatui_ruby/widgets/cursor.rb +54 -0
- data/lib/ratatui_ruby/widgets/gauge.rb +146 -0
- data/lib/ratatui_ruby/widgets/line_gauge.rb +158 -0
- data/lib/ratatui_ruby/widgets/list.rb +252 -0
- data/lib/ratatui_ruby/widgets/list_item.rb +55 -0
- data/lib/ratatui_ruby/widgets/overlay.rb +55 -0
- data/lib/ratatui_ruby/widgets/paragraph.rb +113 -0
- data/lib/ratatui_ruby/widgets/ratatui_logo.rb +35 -0
- data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +40 -0
- data/lib/ratatui_ruby/widgets/row.rb +123 -0
- data/lib/ratatui_ruby/widgets/scrollbar.rb +147 -0
- data/lib/ratatui_ruby/widgets/shape/label.rb +80 -0
- data/lib/ratatui_ruby/widgets/sparkline.rb +153 -0
- data/lib/ratatui_ruby/widgets/table.rb +213 -0
- data/lib/ratatui_ruby/widgets/tabs.rb +91 -0
- data/lib/ratatui_ruby/widgets.rb +43 -0
- data/lib/ratatui_ruby.rb +555 -0
- data/sig/examples/app_all_events/app.rbs +11 -0
- data/sig/examples/app_all_events/model/app_model.rbs +23 -0
- data/sig/examples/app_all_events/model/event_entry.rbs +23 -0
- data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
- data/sig/examples/app_all_events/view/app_view.rbs +8 -0
- data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
- data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
- data/sig/examples/app_all_events/view/live_view.rbs +6 -0
- data/sig/examples/app_all_events/view/log_view.rbs +6 -0
- data/sig/examples/app_all_events/view.rbs +14 -0
- data/sig/examples/app_cli_rich_moments/app.rbs +12 -0
- data/sig/examples/app_color_picker/app.rbs +17 -0
- data/sig/examples/app_external_editor/app.rbs +12 -0
- data/sig/examples/app_login_form/app.rbs +11 -0
- data/sig/examples/app_stateful_interaction/app.rbs +39 -0
- data/sig/examples/verify_quickstart_dsl/app.rbs +17 -0
- data/sig/examples/verify_quickstart_lifecycle/app.rbs +17 -0
- data/sig/examples/verify_readme_usage/app.rbs +17 -0
- data/sig/examples/widget_block_demo/app.rbs +38 -0
- data/sig/examples/widget_box_demo/app.rbs +17 -0
- data/sig/examples/widget_calendar_demo/app.rbs +17 -0
- data/sig/examples/widget_cell_demo/app.rbs +17 -0
- data/sig/examples/widget_chart_demo/app.rbs +17 -0
- data/sig/examples/widget_gauge_demo/app.rbs +17 -0
- data/sig/examples/widget_layout_split/app.rbs +16 -0
- data/sig/examples/widget_line_gauge_demo/app.rbs +17 -0
- data/sig/examples/widget_list_demo/app.rbs +17 -0
- data/sig/examples/widget_map_demo/app.rbs +17 -0
- data/sig/examples/widget_popup_demo/app.rbs +17 -0
- data/sig/examples/widget_ratatui_logo_demo/app.rbs +17 -0
- data/sig/examples/widget_ratatui_mascot_demo/app.rbs +17 -0
- data/sig/examples/widget_rect/app.rbs +18 -0
- data/sig/examples/widget_render/app.rbs +16 -0
- data/sig/examples/widget_rich_text/app.rbs +17 -0
- data/sig/examples/widget_scroll_text/app.rbs +17 -0
- data/sig/examples/widget_scrollbar_demo/app.rbs +17 -0
- data/sig/examples/widget_sparkline_demo/app.rbs +16 -0
- data/sig/examples/widget_style_colors/app.rbs +20 -0
- data/sig/examples/widget_table_demo/app.rbs +17 -0
- data/sig/examples/widget_text_width/app.rbs +16 -0
- data/sig/generated/event_key_predicates.rbs +1348 -0
- data/sig/manifest.yaml +5 -0
- data/sig/patches/data.rbs +26 -0
- data/sig/patches/debugger__.rbs +8 -0
- data/sig/ratatui_ruby/backend/window_size.rbs +17 -0
- data/sig/ratatui_ruby/backend.rbs +12 -0
- data/sig/ratatui_ruby/buffer/cell.rbs +46 -0
- data/sig/ratatui_ruby/buffer.rbs +18 -0
- data/sig/ratatui_ruby/cell.rbs +44 -0
- data/sig/ratatui_ruby/clear.rbs +18 -0
- data/sig/ratatui_ruby/constraint.rbs +26 -0
- data/sig/ratatui_ruby/debug.rbs +45 -0
- data/sig/ratatui_ruby/draw.rbs +30 -0
- data/sig/ratatui_ruby/event.rbs +249 -0
- data/sig/ratatui_ruby/frame.rbs +23 -0
- data/sig/ratatui_ruby/interfaces.rbs +25 -0
- data/sig/ratatui_ruby/labs.rbs +90 -0
- data/sig/ratatui_ruby/layout/alignment.rbs +26 -0
- data/sig/ratatui_ruby/layout/constraint.rbs +39 -0
- data/sig/ratatui_ruby/layout/layout.rbs +45 -0
- data/sig/ratatui_ruby/layout/position.rbs +18 -0
- data/sig/ratatui_ruby/layout/rect.rbs +64 -0
- data/sig/ratatui_ruby/layout/size.rbs +18 -0
- data/sig/ratatui_ruby/list_state.rbs +23 -0
- data/sig/ratatui_ruby/output_guard.rbs +23 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +113 -0
- data/sig/ratatui_ruby/rect.rbs +17 -0
- data/sig/ratatui_ruby/scrollbar_state.rbs +24 -0
- data/sig/ratatui_ruby/session.rbs +93 -0
- data/sig/ratatui_ruby/style/color.rbs +22 -0
- data/sig/ratatui_ruby/style/style.rbs +29 -0
- data/sig/ratatui_ruby/symbols.rbs +141 -0
- data/sig/ratatui_ruby/synthetic_events.rbs +24 -0
- data/sig/ratatui_ruby/table_state.rbs +27 -0
- data/sig/ratatui_ruby/terminal/capabilities.rbs +38 -0
- data/sig/ratatui_ruby/terminal/viewport.rbs +33 -0
- data/sig/ratatui_ruby/terminal_lifecycle.rbs +39 -0
- data/sig/ratatui_ruby/test_helper/event_injection.rbs +22 -0
- data/sig/ratatui_ruby/test_helper/snapshot.rbs +37 -0
- data/sig/ratatui_ruby/test_helper/style_assertions.rbs +77 -0
- data/sig/ratatui_ruby/test_helper/terminal.rbs +20 -0
- data/sig/ratatui_ruby/test_helper/test_doubles.rbs +32 -0
- data/sig/ratatui_ruby/test_helper.rbs +18 -0
- data/sig/ratatui_ruby/text/line.rbs +27 -0
- data/sig/ratatui_ruby/text/span.rbs +23 -0
- data/sig/ratatui_ruby/text.rbs +12 -0
- data/sig/ratatui_ruby/tui/buffer_factories.rbs +16 -0
- data/sig/ratatui_ruby/tui/canvas_factories.rbs +38 -0
- data/sig/ratatui_ruby/tui/core.rbs +23 -0
- data/sig/ratatui_ruby/tui/layout_factories.rbs +39 -0
- data/sig/ratatui_ruby/tui/state_factories.rbs +23 -0
- data/sig/ratatui_ruby/tui/style_factories.rbs +18 -0
- data/sig/ratatui_ruby/tui/text_factories.rbs +23 -0
- data/sig/ratatui_ruby/tui/widget_factories.rbs +138 -0
- data/sig/ratatui_ruby/tui.rbs +25 -0
- data/sig/ratatui_ruby/version.rbs +12 -0
- data/sig/ratatui_ruby/widgets/bar_chart.rbs +95 -0
- data/sig/ratatui_ruby/widgets/block.rbs +51 -0
- data/sig/ratatui_ruby/widgets/calendar.rbs +45 -0
- data/sig/ratatui_ruby/widgets/canvas.rbs +95 -0
- data/sig/ratatui_ruby/widgets/chart.rbs +91 -0
- data/sig/ratatui_ruby/widgets/coerceable_widget.rbs +26 -0
- data/sig/ratatui_ruby/widgets/gauge.rbs +44 -0
- data/sig/ratatui_ruby/widgets/line_gauge.rbs +48 -0
- data/sig/ratatui_ruby/widgets/list.rbs +63 -0
- data/sig/ratatui_ruby/widgets/misc.rbs +158 -0
- data/sig/ratatui_ruby/widgets/paragraph.rbs +45 -0
- data/sig/ratatui_ruby/widgets/row.rbs +43 -0
- data/sig/ratatui_ruby/widgets/scrollbar.rbs +53 -0
- data/sig/ratatui_ruby/widgets/shape/label.rbs +37 -0
- data/sig/ratatui_ruby/widgets/sparkline.rbs +45 -0
- data/sig/ratatui_ruby/widgets/table.rbs +78 -0
- data/sig/ratatui_ruby/widgets/tabs.rbs +44 -0
- data/sig/ratatui_ruby/widgets.rbs +16 -0
- data/vendor/goodcop/base.yml +1047 -0
- metadata +729 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
module RatatuiRuby
|
|
9
|
+
module Layout
|
|
10
|
+
# Divides an area into smaller chunks.
|
|
11
|
+
#
|
|
12
|
+
# Terminal screens vary in size. Hardcoded positions break when the window resizes. You need a way to organize space dynamically.
|
|
13
|
+
#
|
|
14
|
+
# This class manages geometry. It splits a given area into multiple sections based on a list of constraints.
|
|
15
|
+
#
|
|
16
|
+
# Use layouts to build responsive grids. Stack sections vertically for a sidebar-main structure. Partition them horizontally for headers and footers. Let the layout engine do the math.
|
|
17
|
+
#
|
|
18
|
+
# {rdoc-image:/doc/images/widget_layout_split.png}[link:/examples/widget_layout_split/app_rb.html]
|
|
19
|
+
#
|
|
20
|
+
# === Example
|
|
21
|
+
#
|
|
22
|
+
# Run the interactive demo from the terminal:
|
|
23
|
+
#
|
|
24
|
+
# ruby examples/widget_layout_split/app.rb
|
|
25
|
+
class Layout < Data.define(:direction, :constraints, :children, :flex, :margin, :spacing)
|
|
26
|
+
##
|
|
27
|
+
# :attr_reader: direction
|
|
28
|
+
# Direction of the split.
|
|
29
|
+
#
|
|
30
|
+
# Either <tt>:vertical</tt> (top to bottom) or <tt>:horizontal</tt> (left to right).
|
|
31
|
+
#
|
|
32
|
+
# layout.direction # => :vertical
|
|
33
|
+
|
|
34
|
+
##
|
|
35
|
+
# :attr_reader: constraints
|
|
36
|
+
# Array of rules defining section sizes.
|
|
37
|
+
#
|
|
38
|
+
# See RatatuiRuby::Layout::Constraint.
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# :attr_reader: children
|
|
42
|
+
# Widgets to render in each section (optional).
|
|
43
|
+
#
|
|
44
|
+
# If provided, `children[i]` is rendered into the area defined by `constraints[i]`.
|
|
45
|
+
|
|
46
|
+
##
|
|
47
|
+
# :attr_reader: flex
|
|
48
|
+
# Strategy for distributing extra space.
|
|
49
|
+
#
|
|
50
|
+
# One of <tt>:legacy</tt>, <tt>:start</tt>, <tt>:center</tt>, <tt>:end</tt>, <tt>:space_between</tt>, <tt>:space_around</tt>.
|
|
51
|
+
|
|
52
|
+
FLEX_MODES = %i[legacy start center end space_between space_around space_evenly].freeze # :nodoc:
|
|
53
|
+
|
|
54
|
+
##
|
|
55
|
+
# Direction: split vertically (top to bottom).
|
|
56
|
+
DIRECTION_VERTICAL = :vertical
|
|
57
|
+
##
|
|
58
|
+
# Direction: split horizontally (left to right).
|
|
59
|
+
DIRECTION_HORIZONTAL = :horizontal
|
|
60
|
+
|
|
61
|
+
##
|
|
62
|
+
# Flex: use legacy sizing (default).
|
|
63
|
+
FLEX_LEGACY = :legacy
|
|
64
|
+
##
|
|
65
|
+
# Flex: align to start.
|
|
66
|
+
FLEX_START = :start
|
|
67
|
+
##
|
|
68
|
+
# Flex: center alignment.
|
|
69
|
+
FLEX_CENTER = :center
|
|
70
|
+
##
|
|
71
|
+
# Flex: align to end.
|
|
72
|
+
FLEX_END = :end
|
|
73
|
+
##
|
|
74
|
+
# Flex: space between elements.
|
|
75
|
+
FLEX_SPACE_BETWEEN = :space_between
|
|
76
|
+
##
|
|
77
|
+
# Flex: space around elements.
|
|
78
|
+
FLEX_SPACE_AROUND = :space_around
|
|
79
|
+
##
|
|
80
|
+
# Flex: space evenly between elements.
|
|
81
|
+
FLEX_SPACE_EVENLY = :space_evenly
|
|
82
|
+
|
|
83
|
+
##
|
|
84
|
+
# :attr_reader: margin
|
|
85
|
+
# Margin around the layout area.
|
|
86
|
+
#
|
|
87
|
+
# Either a single <tt>Integer</tt> for uniform margin on all sides, or a
|
|
88
|
+
# <tt>Hash</tt> with <tt>:horizontal</tt> and <tt>:vertical</tt> keys.
|
|
89
|
+
#
|
|
90
|
+
# layout.margin # => 2
|
|
91
|
+
|
|
92
|
+
##
|
|
93
|
+
# :attr_reader: spacing
|
|
94
|
+
# Gap between segments (in cells).
|
|
95
|
+
#
|
|
96
|
+
# A positive integer that specifies the number of cells between each segment.
|
|
97
|
+
#
|
|
98
|
+
# layout.spacing # => 1
|
|
99
|
+
|
|
100
|
+
# Creates a new Layout.
|
|
101
|
+
#
|
|
102
|
+
# [direction]
|
|
103
|
+
# <tt>:vertical</tt> or <tt>:horizontal</tt> (default: <tt>:vertical</tt>).
|
|
104
|
+
# [constraints]
|
|
105
|
+
# list of Constraint objects.
|
|
106
|
+
# [children]
|
|
107
|
+
# List of widgets to render (optional).
|
|
108
|
+
# [flex]
|
|
109
|
+
# Flex mode for spacing (default: <tt>:legacy</tt>).
|
|
110
|
+
# [margin]
|
|
111
|
+
# Edge margin in cells (default: <tt>0</tt>).
|
|
112
|
+
# [spacing]
|
|
113
|
+
# Gap between segments in cells (default: <tt>0</tt>).
|
|
114
|
+
def initialize(direction: :vertical, constraints: [], children: [], flex: :legacy, margin: 0, spacing: 0)
|
|
115
|
+
super
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Splits an area into multiple rectangles.
|
|
119
|
+
#
|
|
120
|
+
# This is a pure calculation helper for hit testing. It computes where
|
|
121
|
+
# widgets *would* be placed without actually rendering them.
|
|
122
|
+
#
|
|
123
|
+
#--
|
|
124
|
+
# SPDX-SnippetBegin
|
|
125
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
126
|
+
# SPDX-License-Identifier: MIT-0
|
|
127
|
+
#++
|
|
128
|
+
# rects = Layout::Layout.split(
|
|
129
|
+
# area,
|
|
130
|
+
# direction: :horizontal,
|
|
131
|
+
# constraints: [Layout::Constraint.percentage(50), Layout::Constraint.percentage(50)]
|
|
132
|
+
# )
|
|
133
|
+
# left, right = rects
|
|
134
|
+
#
|
|
135
|
+
#--
|
|
136
|
+
# SPDX-SnippetEnd
|
|
137
|
+
#++
|
|
138
|
+
# [area]
|
|
139
|
+
# The area to split. Can be a <tt>Rect</tt> or a <tt>Hash</tt> containing <tt>:x</tt>, <tt>:y</tt>, <tt>:width</tt>, and <tt>:height</tt>.
|
|
140
|
+
# [direction]
|
|
141
|
+
# <tt>:vertical</tt> or <tt>:horizontal</tt> (default: <tt>:vertical</tt>).
|
|
142
|
+
# [constraints]
|
|
143
|
+
# Array of <tt>Constraint</tt> objects defining section sizes.
|
|
144
|
+
# [flex]
|
|
145
|
+
#--
|
|
146
|
+
# SPDX-SnippetBegin
|
|
147
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
148
|
+
# SPDX-License-Identifier: MIT-0
|
|
149
|
+
#++
|
|
150
|
+
# Flex mode for spacing (default: <tt>:legacy</tt>).
|
|
151
|
+
#
|
|
152
|
+
#--
|
|
153
|
+
# SPDX-SnippetEnd
|
|
154
|
+
#++
|
|
155
|
+
# Returns an Array of <tt>Rect</tt> objects.
|
|
156
|
+
def self.split(area, direction: :vertical, constraints:, flex: :legacy)
|
|
157
|
+
# Coerce area to Rect for type safety (supports duck typing via _RectLike interface)
|
|
158
|
+
rect = case area
|
|
159
|
+
when Rect
|
|
160
|
+
area
|
|
161
|
+
when Hash
|
|
162
|
+
Rect.new(
|
|
163
|
+
x: Integer(area.fetch(:x, 0)),
|
|
164
|
+
y: Integer(area.fetch(:y, 0)),
|
|
165
|
+
width: Integer(area.fetch(:width, 0)),
|
|
166
|
+
height: Integer(area.fetch(:height, 0))
|
|
167
|
+
)
|
|
168
|
+
else
|
|
169
|
+
# Duck typing: accept any object responding to x, y, width, height
|
|
170
|
+
if area.respond_to?(:x) && area.respond_to?(:y) && area.respond_to?(:width) && area.respond_to?(:height)
|
|
171
|
+
# @type var rect_like: _RectLike
|
|
172
|
+
rect_like = area
|
|
173
|
+
Rect.new(x: rect_like.x, y: rect_like.y, width: rect_like.width, height: rect_like.height)
|
|
174
|
+
else
|
|
175
|
+
raise ArgumentError, "area must be a Rect, Hash, or respond to x/y/width/height, got #{area.class}"
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
raw_rects = _split(rect, direction, constraints, flex)
|
|
179
|
+
raw_rects.map { |r| Rect.new(x: r[:x], y: r[:y], width: r[:width], height: r[:height]) }
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Splits an area into multiple rectangles, returning both segments and spacers.
|
|
183
|
+
#
|
|
184
|
+
# Layout splitting returns only the content areas. But some designs need to
|
|
185
|
+
# render content in the gaps (dividers, separators, decorations).
|
|
186
|
+
#
|
|
187
|
+
# This method returns both the segments (content areas) and the spacers
|
|
188
|
+
# (gaps between segments) as separate arrays. The spacers are the Rects
|
|
189
|
+
# that represent the spacing between each segment.
|
|
190
|
+
#
|
|
191
|
+
# Use it to render custom separators or to calculate layout with spacing.
|
|
192
|
+
#
|
|
193
|
+
# [area]
|
|
194
|
+
# The area to split. Can be a <tt>Rect</tt> or a <tt>Hash</tt> containing <tt>:x</tt>, <tt>:y</tt>, <tt>:width</tt>, and <tt>:height</tt>.
|
|
195
|
+
# [direction]
|
|
196
|
+
# <tt>:vertical</tt> or <tt>:horizontal</tt> (default: <tt>:vertical</tt>).
|
|
197
|
+
# [constraints]
|
|
198
|
+
# Array of <tt>Constraint</tt> objects defining section sizes.
|
|
199
|
+
# [flex]
|
|
200
|
+
#--
|
|
201
|
+
# SPDX-SnippetBegin
|
|
202
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
203
|
+
# SPDX-License-Identifier: MIT-0
|
|
204
|
+
#++
|
|
205
|
+
# Flex mode for spacing (default: <tt>:legacy</tt>).
|
|
206
|
+
#
|
|
207
|
+
#--
|
|
208
|
+
# SPDX-SnippetEnd
|
|
209
|
+
#++
|
|
210
|
+
# Returns an Array of two Arrays: <tt>[segments, spacers]</tt>, each containing <tt>Rect</tt> objects.
|
|
211
|
+
#
|
|
212
|
+
# === Example
|
|
213
|
+
#
|
|
214
|
+
#--
|
|
215
|
+
# SPDX-SnippetBegin
|
|
216
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
217
|
+
# SPDX-License-Identifier: MIT-0
|
|
218
|
+
#++
|
|
219
|
+
# area = Rect.new(x: 0, y: 0, width: 100, height: 10)
|
|
220
|
+
# segments, spacers = Layout.split_with_spacers(
|
|
221
|
+
# area,
|
|
222
|
+
# direction: :horizontal,
|
|
223
|
+
# constraints: [Constraint.length(40), Constraint.length(40)],
|
|
224
|
+
# flex: :space_around
|
|
225
|
+
# )
|
|
226
|
+
# # segments: 2 Rects for content
|
|
227
|
+
# # spacers: Rects for gaps between/around segments
|
|
228
|
+
#--
|
|
229
|
+
# SPDX-SnippetEnd
|
|
230
|
+
#++
|
|
231
|
+
def self.split_with_spacers(area, direction: :vertical, constraints:, flex: :legacy)
|
|
232
|
+
# Coerce area to Rect for type safety
|
|
233
|
+
rect = case area
|
|
234
|
+
when Rect
|
|
235
|
+
area
|
|
236
|
+
when Hash
|
|
237
|
+
Rect.new(
|
|
238
|
+
x: Integer(area.fetch(:x, 0)),
|
|
239
|
+
y: Integer(area.fetch(:y, 0)),
|
|
240
|
+
width: Integer(area.fetch(:width, 0)),
|
|
241
|
+
height: Integer(area.fetch(:height, 0))
|
|
242
|
+
)
|
|
243
|
+
else
|
|
244
|
+
if area.respond_to?(:x) && area.respond_to?(:y) && area.respond_to?(:width) && area.respond_to?(:height)
|
|
245
|
+
rect_like = area
|
|
246
|
+
Rect.new(x: rect_like.x, y: rect_like.y, width: rect_like.width, height: rect_like.height)
|
|
247
|
+
else
|
|
248
|
+
raise ArgumentError, "area must be a Rect, Hash, or respond to x/y/width/height, got #{area.class}"
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
raw_segments, raw_spacers = _split_with_spacers(rect, direction, constraints, flex)
|
|
252
|
+
segments = raw_segments.map { |r| Rect.new(x: r[:x], y: r[:y], width: r[:width], height: r[:height]) }
|
|
253
|
+
spacers = raw_spacers.map { |r| Rect.new(x: r[:x], y: r[:y], width: r[:width], height: r[:height]) }
|
|
254
|
+
[segments, spacers]
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
module RatatuiRuby
|
|
9
|
+
module Layout
|
|
10
|
+
# A position in terminal coordinates.
|
|
11
|
+
#
|
|
12
|
+
# Layout code passes x/y pairs between functions. Bundling them
|
|
13
|
+
# into separate variables is verbose and prone to ordering mistakes.
|
|
14
|
+
#
|
|
15
|
+
# This class wraps column and row into a single immutable object.
|
|
16
|
+
# Pass it around, destructure it, or convert from a Rect.
|
|
17
|
+
#
|
|
18
|
+
# Use it for cursor positioning, mouse coordinates, or anywhere
|
|
19
|
+
# you need to represent a single point on the terminal grid.
|
|
20
|
+
#
|
|
21
|
+
# === Example
|
|
22
|
+
#
|
|
23
|
+
#--
|
|
24
|
+
# SPDX-SnippetBegin
|
|
25
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
26
|
+
# SPDX-License-Identifier: MIT-0
|
|
27
|
+
#++
|
|
28
|
+
# pos = Layout::Position.new(x: 10, y: 5)
|
|
29
|
+
# puts "Cursor at column #{pos.x}, row #{pos.y}"
|
|
30
|
+
#
|
|
31
|
+
# # Extract from a Rect
|
|
32
|
+
# rect = Layout::Rect.new(x: 10, y: 5, width: 80, height: 24)
|
|
33
|
+
# pos = rect.as_position # => Position(x: 10, y: 5)
|
|
34
|
+
#--
|
|
35
|
+
# SPDX-SnippetEnd
|
|
36
|
+
#++
|
|
37
|
+
class Position < Data.define(:x, :y)
|
|
38
|
+
##
|
|
39
|
+
# :attr_reader: x
|
|
40
|
+
# Column index (0-indexed from left edge).
|
|
41
|
+
|
|
42
|
+
##
|
|
43
|
+
# :attr_reader: y
|
|
44
|
+
# Row index (0-indexed from top edge).
|
|
45
|
+
|
|
46
|
+
# Creates a new Position.
|
|
47
|
+
#
|
|
48
|
+
# [x] Column index (Integer, coerced via +Integer()+).
|
|
49
|
+
# [y] Row index (Integer, coerced via +Integer()+).
|
|
50
|
+
def initialize(x: 0, y: 0)
|
|
51
|
+
super(x: Integer(x), y: Integer(y))
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Enables array destructuring for convenient coordinate extraction.
|
|
55
|
+
#
|
|
56
|
+
# Returns:: Array of [x, y] coordinates.
|
|
57
|
+
#
|
|
58
|
+
# === Example
|
|
59
|
+
#
|
|
60
|
+
#--
|
|
61
|
+
# SPDX-SnippetBegin
|
|
62
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
63
|
+
# SPDX-License-Identifier: MIT-0
|
|
64
|
+
#++
|
|
65
|
+
# pos = Position.new(x: 10, y: 5)
|
|
66
|
+
# x, y = pos # Uses deconstruct
|
|
67
|
+
# puts "Column: #{x}, Row: #{y}"
|
|
68
|
+
#--
|
|
69
|
+
# SPDX-SnippetEnd
|
|
70
|
+
#++
|
|
71
|
+
def deconstruct
|
|
72
|
+
[x, y]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Alias for implicit array conversion.
|
|
76
|
+
#
|
|
77
|
+
# Enables `x, y = position` syntax by making Position respond to +to_ary+.
|
|
78
|
+
alias to_ary deconstruct
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|