ratatui_ruby 0.4.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 +98 -176
- data/CHANGELOG.md +80 -6
- data/README.md +19 -7
- data/REUSE.toml +15 -0
- data/doc/application_architecture.md +179 -45
- data/doc/application_testing.md +80 -32
- data/doc/contributors/design/ruby_frontend.md +48 -8
- data/doc/contributors/design/rust_backend.md +1 -0
- data/doc/contributors/developing_examples.md +191 -48
- data/doc/contributors/documentation_style.md +7 -0
- 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/contributors/index.md +2 -0
- data/doc/event_handling.md +21 -7
- 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_box_demo.png +0 -0
- data/doc/images/widget_calendar_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_gauge_demo.png +0 -0
- data/doc/images/widget_layout_split.png +0 -0
- data/doc/images/widget_line_gauge_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_ratatui_logo_demo.png +0 -0
- data/doc/images/widget_ratatui_mascot_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_scrollbar_demo.png +0 -0
- data/doc/images/widget_sparkline_demo.png +0 -0
- data/doc/images/widget_style_colors.png +0 -0
- data/doc/images/widget_table_demo.png +0 -0
- data/doc/images/widget_table_flex.png +0 -0
- data/doc/images/widget_tabs_demo.png +0 -0
- data/doc/images/widget_text_width.png +0 -0
- data/doc/interactive_design.md +25 -30
- data/doc/quickstart.md +150 -130
- data/doc/terminal_limitations.md +92 -0
- data/examples/app_all_events/README.md +99 -0
- data/examples/app_all_events/app.rb +96 -0
- data/examples/app_all_events/model/app_model.rb +157 -0
- data/examples/app_all_events/model/event_color_cycle.rb +41 -0
- data/examples/app_all_events/model/event_entry.rb +92 -0
- data/examples/app_all_events/model/msg.rb +37 -0
- data/examples/app_all_events/model/timestamp.rb +54 -0
- data/examples/app_all_events/update.rb +73 -0
- data/examples/app_all_events/view/app_view.rb +78 -0
- data/examples/app_all_events/view/controls_view.rb +52 -0
- data/examples/app_all_events/view/counts_view.rb +59 -0
- data/examples/app_all_events/view/live_view.rb +70 -0
- data/examples/app_all_events/view/log_view.rb +55 -0
- data/examples/app_all_events/view.rb +7 -0
- data/examples/app_color_picker/README.md +134 -0
- data/examples/app_color_picker/app.rb +74 -0
- data/examples/app_color_picker/clipboard.rb +84 -0
- data/examples/app_color_picker/color.rb +191 -0
- data/examples/app_color_picker/controls.rb +90 -0
- data/examples/app_color_picker/copy_dialog.rb +166 -0
- data/examples/app_color_picker/export_pane.rb +126 -0
- data/examples/app_color_picker/harmony.rb +56 -0
- data/examples/app_color_picker/input.rb +174 -0
- data/examples/app_color_picker/main_container.rb +178 -0
- data/examples/app_color_picker/palette.rb +109 -0
- data/examples/app_login_form/README.md +47 -0
- data/examples/{login_form → app_login_form}/app.rb +38 -42
- 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/{quickstart_dsl → verify_quickstart_dsl}/app.rb +17 -6
- data/examples/verify_quickstart_layout/README.md +71 -0
- data/examples/verify_quickstart_layout/app.rb +71 -0
- data/examples/verify_quickstart_lifecycle/README.md +56 -0
- data/examples/verify_quickstart_lifecycle/app.rb +54 -0
- data/examples/verify_readme_usage/README.md +43 -0
- data/examples/verify_readme_usage/app.rb +40 -0
- data/examples/widget_barchart_demo/README.md +49 -0
- data/examples/widget_barchart_demo/app.rb +238 -0
- 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/{box_demo → widget_box_demo}/app.rb +99 -65
- data/examples/widget_calendar_demo/README.md +39 -0
- data/examples/widget_calendar_demo/app.rb +109 -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 +111 -0
- 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 +218 -0
- data/examples/widget_gauge_demo/README.md +41 -0
- data/examples/widget_gauge_demo/app.rb +212 -0
- data/examples/widget_layout_split/README.md +44 -0
- data/examples/widget_layout_split/app.rb +246 -0
- data/examples/widget_line_gauge_demo/README.md +41 -0
- data/examples/widget_line_gauge_demo/app.rb +217 -0
- data/examples/widget_list_demo/README.md +49 -0
- data/examples/widget_list_demo/app.rb +366 -0
- data/examples/widget_map_demo/README.md +39 -0
- data/examples/{map_demo → widget_map_demo}/app.rb +24 -21
- data/examples/widget_overlay_demo/app.rb +248 -0
- data/examples/widget_popup_demo/README.md +36 -0
- data/examples/widget_popup_demo/app.rb +104 -0
- data/examples/widget_ratatui_logo_demo/README.md +34 -0
- data/examples/widget_ratatui_logo_demo/app.rb +103 -0
- data/examples/widget_ratatui_mascot_demo/README.md +34 -0
- data/examples/widget_ratatui_mascot_demo/app.rb +93 -0
- data/examples/widget_rect/README.md +38 -0
- data/examples/widget_rect/app.rb +205 -0
- data/examples/widget_render/README.md +37 -0
- data/examples/widget_render/app.rb +184 -0
- data/examples/widget_rich_text/README.md +35 -0
- data/examples/widget_rich_text/app.rb +166 -0
- data/examples/widget_scroll_text/README.md +37 -0
- data/examples/widget_scroll_text/app.rb +107 -0
- data/examples/widget_scrollbar_demo/README.md +37 -0
- data/examples/widget_scrollbar_demo/app.rb +153 -0
- data/examples/widget_sparkline_demo/README.md +42 -0
- data/examples/widget_sparkline_demo/app.rb +275 -0
- data/examples/widget_style_colors/README.md +34 -0
- data/examples/widget_style_colors/app.rb +19 -21
- data/examples/widget_table_demo/README.md +48 -0
- data/examples/widget_table_demo/app.rb +239 -0
- data/examples/widget_tabs_demo/README.md +41 -0
- data/examples/widget_tabs_demo/app.rb +181 -0
- data/examples/widget_text_width/README.md +35 -0
- data/examples/widget_text_width/app.rb +106 -0
- data/ext/ratatui_ruby/Cargo.lock +11 -4
- data/ext/ratatui_ruby/Cargo.toml +2 -1
- data/ext/ratatui_ruby/src/events.rs +359 -62
- data/ext/ratatui_ruby/src/frame.rs +227 -0
- data/ext/ratatui_ruby/src/lib.rs +110 -27
- data/ext/ratatui_ruby/src/rendering.rs +8 -4
- data/ext/ratatui_ruby/src/string_width.rs +101 -0
- data/ext/ratatui_ruby/src/style.rs +138 -57
- data/ext/ratatui_ruby/src/terminal.rs +42 -22
- data/ext/ratatui_ruby/src/text.rs +14 -7
- data/ext/ratatui_ruby/src/widgets/barchart.rs +74 -54
- data/ext/ratatui_ruby/src/widgets/block.rs +7 -6
- data/ext/ratatui_ruby/src/widgets/canvas.rs +21 -3
- data/ext/ratatui_ruby/src/widgets/chart.rs +20 -10
- data/ext/ratatui_ruby/src/widgets/gauge.rs +9 -2
- data/ext/ratatui_ruby/src/widgets/layout.rs +9 -4
- data/ext/ratatui_ruby/src/widgets/line_gauge.rs +9 -2
- data/ext/ratatui_ruby/src/widgets/list.rs +211 -12
- 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/overlay.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/paragraph.rs +1 -1
- data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +19 -8
- data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +17 -10
- data/ext/ratatui_ruby/src/widgets/scrollbar.rs +97 -3
- data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
- data/ext/ratatui_ruby/src/widgets/sparkline.rs +14 -11
- data/ext/ratatui_ruby/src/widgets/table.rs +121 -5
- data/ext/ratatui_ruby/src/widgets/table_state.rs +121 -0
- data/ext/ratatui_ruby/src/widgets/tabs.rs +11 -11
- data/lib/ratatui_ruby/cell.rb +7 -7
- 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 +112 -52
- data/lib/ratatui_ruby/event/mouse.rb +3 -3
- data/lib/ratatui_ruby/event/none.rb +43 -0
- data/lib/ratatui_ruby/event/paste.rb +1 -1
- data/lib/ratatui_ruby/event.rb +56 -4
- data/lib/ratatui_ruby/frame.rb +183 -0
- data/lib/ratatui_ruby/list_state.rb +88 -0
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +13 -13
- data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +1 -5
- data/lib/ratatui_ruby/schema/bar_chart.rb +217 -217
- data/lib/ratatui_ruby/schema/block.rb +163 -168
- data/lib/ratatui_ruby/schema/calendar.rb +66 -67
- data/lib/ratatui_ruby/schema/canvas.rb +63 -63
- data/lib/ratatui_ruby/schema/center.rb +46 -46
- data/lib/ratatui_ruby/schema/chart.rb +135 -143
- data/lib/ratatui_ruby/schema/clear.rb +42 -42
- data/lib/ratatui_ruby/schema/constraint.rb +76 -76
- data/lib/ratatui_ruby/schema/cursor.rb +30 -25
- data/lib/ratatui_ruby/schema/gauge.rb +54 -52
- data/lib/ratatui_ruby/schema/layout.rb +87 -87
- data/lib/ratatui_ruby/schema/line_gauge.rb +62 -62
- data/lib/ratatui_ruby/schema/list.rb +103 -80
- data/lib/ratatui_ruby/schema/list_item.rb +41 -0
- data/lib/ratatui_ruby/schema/overlay.rb +31 -31
- data/lib/ratatui_ruby/schema/paragraph.rb +80 -80
- data/lib/ratatui_ruby/schema/ratatui_logo.rb +10 -6
- data/lib/ratatui_ruby/schema/ratatui_mascot.rb +10 -5
- data/lib/ratatui_ruby/schema/rect.rb +99 -56
- data/lib/ratatui_ruby/schema/scrollbar.rb +119 -119
- data/lib/ratatui_ruby/schema/shape/label.rb +1 -1
- data/lib/ratatui_ruby/schema/sparkline.rb +111 -110
- data/lib/ratatui_ruby/schema/style.rb +66 -46
- data/lib/ratatui_ruby/schema/table.rb +126 -115
- data/lib/ratatui_ruby/schema/tabs.rb +66 -67
- 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 +482 -0
- data/lib/ratatui_ruby/session.rb +55 -23
- 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 +66 -193
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby.rb +100 -51
- data/{examples/sparkline_demo → sig/examples/app_all_events}/app.rbs +3 -2
- data/sig/examples/app_all_events/model/event_entry.rbs +16 -0
- data/sig/examples/app_all_events/model/events.rbs +15 -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 +8 -0
- data/sig/examples/app_all_events/view_state.rbs +15 -0
- data/{examples/list_demo → sig/examples/app_color_picker}/app.rbs +2 -2
- data/sig/examples/app_login_form/app.rbs +11 -0
- data/sig/examples/app_stateful_interaction/app.rbs +33 -0
- data/sig/examples/verify_quickstart_dsl/app.rbs +11 -0
- data/sig/examples/verify_quickstart_lifecycle/app.rbs +11 -0
- data/sig/examples/verify_readme_usage/app.rbs +11 -0
- data/sig/examples/widget_block_demo/app.rbs +32 -0
- data/sig/examples/widget_box_demo/app.rbs +11 -0
- data/sig/examples/widget_calendar_demo/app.rbs +11 -0
- data/sig/examples/widget_cell_demo/app.rbs +11 -0
- data/sig/examples/widget_chart_demo/app.rbs +11 -0
- data/{examples/gauge_demo → sig/examples/widget_gauge_demo}/app.rbs +4 -0
- data/sig/examples/widget_layout_split/app.rbs +10 -0
- data/sig/examples/widget_line_gauge_demo/app.rbs +11 -0
- data/sig/examples/widget_list_demo/app.rbs +12 -0
- data/sig/examples/widget_map_demo/app.rbs +11 -0
- data/sig/examples/widget_popup_demo/app.rbs +11 -0
- data/sig/examples/widget_ratatui_logo_demo/app.rbs +11 -0
- data/sig/examples/widget_ratatui_mascot_demo/app.rbs +11 -0
- data/sig/examples/widget_rect/app.rbs +12 -0
- data/sig/examples/widget_render/app.rbs +10 -0
- data/sig/examples/widget_rich_text/app.rbs +11 -0
- data/sig/examples/widget_scroll_text/app.rbs +11 -0
- data/sig/examples/widget_scrollbar_demo/app.rbs +11 -0
- data/sig/examples/widget_sparkline_demo/app.rbs +10 -0
- data/{examples → sig/examples}/widget_style_colors/app.rbs +1 -1
- data/sig/examples/widget_table_demo/app.rbs +11 -0
- data/sig/examples/widget_text_width/app.rbs +10 -0
- data/sig/ratatui_ruby/event.rbs +11 -1
- data/sig/ratatui_ruby/frame.rbs +11 -0
- data/sig/ratatui_ruby/list_state.rbs +13 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +5 -4
- data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +3 -3
- data/sig/ratatui_ruby/schema/draw.rbs +4 -0
- data/sig/ratatui_ruby/schema/gauge.rbs +2 -2
- data/sig/ratatui_ruby/schema/layout.rbs +1 -1
- 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 +107 -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 +63 -0
- data/tasks/autodoc/member.rb +56 -0
- data/tasks/autodoc/name.rb +19 -0
- data/tasks/autodoc/notice.rb +26 -0
- data/tasks/autodoc/rbs.rb +38 -0
- data/tasks/autodoc/rdoc.rb +45 -0
- data/tasks/autodoc.rake +53 -0
- data/tasks/bump/changelog.rb +3 -3
- data/tasks/bump/history.rb +2 -2
- data/tasks/bump/links.rb +67 -0
- data/tasks/doc.rake +600 -6
- data/tasks/example_viewer.html.erb +172 -0
- data/tasks/lint.rake +8 -4
- data/tasks/resources/index.html.erb +6 -0
- data/tasks/sourcehut.rake +70 -30
- data/tasks/terminal_preview/app_screenshot.rb +14 -6
- data/tasks/terminal_preview/crash_report.rb +7 -9
- data/tasks/terminal_preview/launcher_script.rb +4 -6
- data/tasks/terminal_preview/preview_collection.rb +4 -6
- data/tasks/terminal_preview/safety_confirmation.rb +3 -5
- data/tasks/terminal_preview/saved_screenshot.rb +10 -11
- data/tasks/terminal_preview/terminal_window.rb +7 -9
- data/tasks/test.rake +1 -1
- data/tasks/website/index_page.rb +3 -3
- data/tasks/website/version.rb +10 -10
- data/tasks/website/version_menu.rb +10 -12
- data/tasks/website/versioned_documentation.rb +49 -17
- data/tasks/website/website.rb +6 -8
- data/tasks/website.rake +4 -4
- metadata +232 -127
- data/LICENSES/BSD-2-Clause.txt +0 -9
- data/doc/contributors/better_dx.md +0 -543
- data/doc/contributors/example_analysis.md +0 -82
- data/doc/images/all_events.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/flex_layout.png +0 -0
- data/doc/images/gauge_demo.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/quickstart_dsl.png +0 -0
- data/doc/images/quickstart_lifecycle.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/examples/all_events/app.rb +0 -169
- data/examples/all_events/app.rbs +0 -7
- data/examples/all_events/test_app.rb +0 -139
- data/examples/analytics/app.rb +0 -258
- data/examples/analytics/app.rbs +0 -7
- data/examples/analytics/test_app.rb +0 -132
- data/examples/block_padding/app.rb +0 -63
- data/examples/block_padding/app.rbs +0 -7
- data/examples/block_padding/test_app.rb +0 -31
- data/examples/block_titles/app.rb +0 -61
- data/examples/block_titles/app.rbs +0 -7
- data/examples/block_titles/test_app.rb +0 -34
- data/examples/box_demo/app.rbs +0 -7
- data/examples/box_demo/test_app.rb +0 -88
- data/examples/calendar_demo/app.rb +0 -101
- data/examples/calendar_demo/app.rbs +0 -7
- data/examples/calendar_demo/test_app.rb +0 -108
- data/examples/cell_demo/app.rb +0 -108
- data/examples/cell_demo/app.rbs +0 -7
- data/examples/cell_demo/test_app.rb +0 -36
- data/examples/chart_demo/app.rb +0 -203
- data/examples/chart_demo/app.rbs +0 -7
- data/examples/chart_demo/test_app.rb +0 -102
- data/examples/custom_widget/app.rb +0 -51
- data/examples/custom_widget/app.rbs +0 -7
- data/examples/custom_widget/test_app.rb +0 -30
- data/examples/flex_layout/app.rb +0 -156
- data/examples/flex_layout/app.rbs +0 -7
- data/examples/flex_layout/test_app.rb +0 -65
- data/examples/gauge_demo/app.rb +0 -182
- data/examples/gauge_demo/test_app.rb +0 -120
- data/examples/hit_test/app.rb +0 -175
- data/examples/hit_test/app.rbs +0 -7
- data/examples/hit_test/test_app.rb +0 -102
- data/examples/line_gauge_demo/app.rb +0 -190
- data/examples/line_gauge_demo/app.rbs +0 -7
- data/examples/line_gauge_demo/test_app.rb +0 -129
- data/examples/list_demo/app.rb +0 -253
- data/examples/list_demo/test_app.rb +0 -237
- data/examples/list_styles/app.rb +0 -140
- data/examples/list_styles/app.rbs +0 -7
- data/examples/list_styles/test_app.rb +0 -157
- data/examples/login_form/app.rbs +0 -7
- data/examples/login_form/test_app.rb +0 -51
- data/examples/map_demo/app.rbs +0 -7
- data/examples/map_demo/test_app.rb +0 -149
- data/examples/mouse_events/app.rb +0 -97
- data/examples/mouse_events/app.rbs +0 -7
- data/examples/mouse_events/test_app.rb +0 -53
- data/examples/popup_demo/app.rb +0 -103
- data/examples/popup_demo/app.rbs +0 -7
- data/examples/popup_demo/test_app.rb +0 -54
- data/examples/quickstart_dsl/app.rbs +0 -7
- data/examples/quickstart_dsl/test_app.rb +0 -29
- data/examples/quickstart_lifecycle/app.rb +0 -39
- data/examples/quickstart_lifecycle/app.rbs +0 -7
- data/examples/quickstart_lifecycle/test_app.rb +0 -29
- data/examples/ratatui_logo_demo/app.rb +0 -79
- data/examples/ratatui_logo_demo/app.rbs +0 -7
- data/examples/ratatui_logo_demo/test_app.rb +0 -51
- data/examples/ratatui_mascot_demo/app.rb +0 -84
- data/examples/ratatui_mascot_demo/app.rbs +0 -7
- data/examples/ratatui_mascot_demo/test_app.rb +0 -47
- data/examples/readme_usage/app.rb +0 -29
- data/examples/readme_usage/app.rbs +0 -7
- data/examples/readme_usage/test_app.rb +0 -29
- data/examples/rich_text/app.rb +0 -141
- data/examples/rich_text/app.rbs +0 -7
- data/examples/rich_text/test_app.rb +0 -166
- data/examples/scroll_text/app.rb +0 -103
- data/examples/scroll_text/app.rbs +0 -7
- data/examples/scroll_text/test_app.rb +0 -110
- data/examples/scrollbar_demo/app.rb +0 -143
- data/examples/scrollbar_demo/app.rbs +0 -7
- data/examples/scrollbar_demo/test_app.rb +0 -77
- data/examples/sparkline_demo/app.rb +0 -240
- data/examples/sparkline_demo/test_app.rb +0 -107
- data/examples/table_flex/app.rb +0 -65
- data/examples/table_flex/app.rbs +0 -7
- data/examples/table_flex/test_app.rb +0 -36
- data/examples/table_select/app.rb +0 -198
- data/examples/table_select/app.rbs +0 -7
- data/examples/table_select/test_app.rb +0 -180
- data/examples/widget_style_colors/test_app.rb +0 -48
- data/tasks/bump/comparison_links.rb +0 -41
- /data/doc/images/{analytics.png → app_analytics.png} +0 -0
- /data/doc/images/{custom_widget.png → app_custom_widget.png} +0 -0
- /data/doc/images/{mouse_events.png → app_mouse_events.png} +0 -0
- /data/doc/images/{map_demo.png → widget_map_demo.png} +0 -0
- /data/doc/images/{popup_demo.png → widget_popup_demo.png} +0 -0
- /data/doc/images/{hit_test.png → widget_rect.png} +0 -0
- /data/{doc/images/ratatui_logo_demo.png → exe/.gitkeep} +0 -0
|
@@ -0,0 +1,217 @@
|
|
|
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
|
+
# Demonstrates compact status visualization with interactive attribute cycling.
|
|
10
|
+
#
|
|
11
|
+
# Screen space is precious. Standard block gauges are bulky and consume multiple rows.
|
|
12
|
+
#
|
|
13
|
+
# This demo showcases the <tt>LineGauge</tt> widget. It provides an interactive playground where you can cycle through different ratios, symbols, and styling for both filled and unfilled portions in real-time.
|
|
14
|
+
#
|
|
15
|
+
# Use it to understand how to provide status feedback in constrained layouts without consuming vertical space.
|
|
16
|
+
#
|
|
17
|
+
# === Example
|
|
18
|
+
#
|
|
19
|
+
# Run the demo from the terminal:
|
|
20
|
+
#
|
|
21
|
+
# ruby examples/widget_line_gauge_demo/app.rb
|
|
22
|
+
#
|
|
23
|
+
# rdoc-image:/doc/images/widget_line_gauge_demo.png
|
|
24
|
+
class WidgetLineGaugeDemo
|
|
25
|
+
def initialize
|
|
26
|
+
@ratio = 0.5
|
|
27
|
+
@ratios = [0.2, 0.35, 0.5, 0.65, 0.8, 0.95]
|
|
28
|
+
@ratio_index = 2
|
|
29
|
+
|
|
30
|
+
@filled_symbols = [
|
|
31
|
+
{ name: "█ (Block)", symbol: "█" },
|
|
32
|
+
{ name: "▓ (Dark Shade)", symbol: "▓" },
|
|
33
|
+
{ name: "▒ (Medium Shade)", symbol: "▒" },
|
|
34
|
+
{ name: "= (Equals)", symbol: "=" },
|
|
35
|
+
{ name: "# (Hash)", symbol: "#" },
|
|
36
|
+
]
|
|
37
|
+
@filled_symbol_index = 0
|
|
38
|
+
|
|
39
|
+
@unfilled_symbols = [
|
|
40
|
+
{ name: "░ (Light Shade)", symbol: "░" },
|
|
41
|
+
{ name: "· (Dot)", symbol: "·" },
|
|
42
|
+
{ name: "- (Dash)", symbol: "-" },
|
|
43
|
+
{ name: "~ (Tilde)", symbol: "~" },
|
|
44
|
+
]
|
|
45
|
+
@unfilled_symbol_index = 0
|
|
46
|
+
|
|
47
|
+
@filled_colors = [
|
|
48
|
+
{ name: "Red", color: :red },
|
|
49
|
+
{ name: "Yellow", color: :yellow },
|
|
50
|
+
{ name: "Green", color: :green },
|
|
51
|
+
{ name: "Cyan", color: :cyan },
|
|
52
|
+
{ name: "Blue", color: :blue },
|
|
53
|
+
]
|
|
54
|
+
@filled_color_index = 2
|
|
55
|
+
|
|
56
|
+
@unfilled_colors = [
|
|
57
|
+
{ name: "Default", color: nil },
|
|
58
|
+
{ name: "Dark Gray", color: :dark_gray },
|
|
59
|
+
{ name: "Gray", color: :gray },
|
|
60
|
+
]
|
|
61
|
+
@unfilled_color_index = 1
|
|
62
|
+
|
|
63
|
+
@base_styles = nil # Initialized in run when @tui is available
|
|
64
|
+
@base_style_index = 0
|
|
65
|
+
@hotkey_style = nil # Initialized in run when @tui is available
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def run
|
|
69
|
+
RatatuiRuby.run do |tui|
|
|
70
|
+
@tui = tui
|
|
71
|
+
|
|
72
|
+
# Initialize styles using tui helpers
|
|
73
|
+
@base_styles = [
|
|
74
|
+
{ name: "None", style: nil },
|
|
75
|
+
{ name: "Bold White", style: tui.style(fg: :white, modifiers: [:bold]) },
|
|
76
|
+
{ name: "White on Blue", style: tui.style(fg: :white, bg: :blue) },
|
|
77
|
+
{ name: "Italic Cyan", style: tui.style(fg: :cyan, modifiers: [:italic]) },
|
|
78
|
+
]
|
|
79
|
+
@hotkey_style = tui.style(modifiers: [:bold, :underlined])
|
|
80
|
+
|
|
81
|
+
loop do
|
|
82
|
+
render
|
|
83
|
+
break if handle_input == :quit
|
|
84
|
+
sleep 0.05
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private def render
|
|
90
|
+
@ratio = @ratios[@ratio_index]
|
|
91
|
+
|
|
92
|
+
filled_color = @filled_colors[@filled_color_index][:color]
|
|
93
|
+
unfilled_color = @unfilled_colors[@unfilled_color_index][:color]
|
|
94
|
+
|
|
95
|
+
filled_style = filled_color ? @tui.style(fg: filled_color) : @tui.style(fg: :white)
|
|
96
|
+
unfilled_style = unfilled_color ? @tui.style(fg: unfilled_color) : @tui.style(fg: :dark_gray)
|
|
97
|
+
|
|
98
|
+
@tui.draw do |frame|
|
|
99
|
+
# Split into main content and control panel
|
|
100
|
+
main_area, controls_area = @tui.layout_split(
|
|
101
|
+
frame.area,
|
|
102
|
+
direction: :vertical,
|
|
103
|
+
constraints: [
|
|
104
|
+
@tui.constraint_fill(1),
|
|
105
|
+
@tui.constraint_length(5),
|
|
106
|
+
]
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Split main area into title, gauges, and spacer
|
|
110
|
+
title_area, gauge1_area, gauge2_area, spacer_area = @tui.layout_split(
|
|
111
|
+
main_area,
|
|
112
|
+
direction: :vertical,
|
|
113
|
+
constraints: [
|
|
114
|
+
@tui.constraint_length(1),
|
|
115
|
+
@tui.constraint_length(4),
|
|
116
|
+
@tui.constraint_length(4),
|
|
117
|
+
@tui.constraint_fill(1),
|
|
118
|
+
]
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Render title
|
|
122
|
+
title = @tui.paragraph(text: "LineGauge Widget Demo - Cycle attributes with hotkeys")
|
|
123
|
+
frame.render_widget(title, title_area)
|
|
124
|
+
|
|
125
|
+
# Example 1: Static gauge showing all features
|
|
126
|
+
gauge1 = @tui.line_gauge(
|
|
127
|
+
ratio: @ratio,
|
|
128
|
+
label: "#{(@ratio * 100).to_i}%",
|
|
129
|
+
style: @base_styles[@base_style_index][:style],
|
|
130
|
+
filled_style:,
|
|
131
|
+
unfilled_style:,
|
|
132
|
+
filled_symbol: @filled_symbols[@filled_symbol_index][:symbol],
|
|
133
|
+
unfilled_symbol: @unfilled_symbols[@unfilled_symbol_index][:symbol],
|
|
134
|
+
block: @tui.block(title: "Interactive Gauge")
|
|
135
|
+
)
|
|
136
|
+
frame.render_widget(gauge1, gauge1_area)
|
|
137
|
+
|
|
138
|
+
# Example 2: Inverted colors for contrast demonstration
|
|
139
|
+
gauge2 = @tui.line_gauge(
|
|
140
|
+
ratio: 1.0 - @ratio,
|
|
141
|
+
label: "#{((1.0 - @ratio) * 100).to_i}%",
|
|
142
|
+
filled_style: @tui.style(fg: :black, bg: :yellow),
|
|
143
|
+
unfilled_style: @tui.style(fg: :white, bg: :dark_gray),
|
|
144
|
+
filled_symbol: @filled_symbols[@filled_symbol_index][:symbol],
|
|
145
|
+
unfilled_symbol: @unfilled_symbols[@unfilled_symbol_index][:symbol],
|
|
146
|
+
block: @tui.block(title: "Inverse (100% - ratio)")
|
|
147
|
+
)
|
|
148
|
+
frame.render_widget(gauge2, gauge2_area)
|
|
149
|
+
|
|
150
|
+
# Render empty spacer
|
|
151
|
+
spacer = @tui.paragraph(text: "")
|
|
152
|
+
frame.render_widget(spacer, spacer_area)
|
|
153
|
+
|
|
154
|
+
# Bottom control panel
|
|
155
|
+
controls = @tui.block(
|
|
156
|
+
title: "Controls",
|
|
157
|
+
borders: [:all],
|
|
158
|
+
children: [
|
|
159
|
+
@tui.paragraph(
|
|
160
|
+
text: [
|
|
161
|
+
# Line 1: General
|
|
162
|
+
@tui.text_line(spans: [
|
|
163
|
+
@tui.text_span(content: "←/→", style: @hotkey_style),
|
|
164
|
+
@tui.text_span(content: ": Ratio (#{(@ratio * 100).to_i}%) "),
|
|
165
|
+
@tui.text_span(content: "b", style: @hotkey_style),
|
|
166
|
+
@tui.text_span(content: ": Base Style (#{@base_styles[@base_style_index][:name]}) "),
|
|
167
|
+
@tui.text_span(content: "q", style: @hotkey_style),
|
|
168
|
+
@tui.text_span(content: ": Quit"),
|
|
169
|
+
]),
|
|
170
|
+
# Line 2: Filled
|
|
171
|
+
@tui.text_line(spans: [
|
|
172
|
+
@tui.text_span(content: "f", style: @hotkey_style),
|
|
173
|
+
@tui.text_span(content: ": Filled Symbol (#{@filled_symbols[@filled_symbol_index][:name]}) "),
|
|
174
|
+
@tui.text_span(content: "c", style: @hotkey_style),
|
|
175
|
+
@tui.text_span(content: ": Filled Color (#{@filled_colors[@filled_color_index][:name]})"),
|
|
176
|
+
]),
|
|
177
|
+
# Line 3: Unfilled
|
|
178
|
+
@tui.text_line(spans: [
|
|
179
|
+
@tui.text_span(content: "u", style: @hotkey_style),
|
|
180
|
+
@tui.text_span(content: ": Unfilled Symbol (#{@unfilled_symbols[@unfilled_symbol_index][:name]}) "),
|
|
181
|
+
@tui.text_span(content: "x", style: @hotkey_style),
|
|
182
|
+
@tui.text_span(content: ": Unfilled Color (#{@unfilled_colors[@unfilled_color_index][:name]})"),
|
|
183
|
+
]),
|
|
184
|
+
]
|
|
185
|
+
),
|
|
186
|
+
]
|
|
187
|
+
)
|
|
188
|
+
frame.render_widget(controls, controls_area)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
private def handle_input
|
|
193
|
+
case @tui.poll_event
|
|
194
|
+
in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
|
|
195
|
+
:quit
|
|
196
|
+
in type: :key, code: "right"
|
|
197
|
+
@ratio_index = (@ratio_index + 1) % @ratios.length
|
|
198
|
+
in type: :key, code: "left"
|
|
199
|
+
@ratio_index = (@ratio_index - 1) % @ratios.length
|
|
200
|
+
in type: :key, code: "b"
|
|
201
|
+
@base_style_index = (@base_style_index + 1) % @base_styles.length
|
|
202
|
+
in type: :key, code: "f"
|
|
203
|
+
@filled_symbol_index = (@filled_symbol_index + 1) % @filled_symbols.length
|
|
204
|
+
in type: :key, code: "c"
|
|
205
|
+
@filled_color_index = (@filled_color_index + 1) % @filled_colors.length
|
|
206
|
+
in type: :key, code: "u"
|
|
207
|
+
@unfilled_symbol_index = (@unfilled_symbol_index + 1) % @unfilled_symbols.length
|
|
208
|
+
in type: :key, code: "x"
|
|
209
|
+
@unfilled_color_index = (@unfilled_color_index + 1) % @unfilled_colors.length
|
|
210
|
+
else
|
|
211
|
+
# Ignore other events
|
|
212
|
+
nil
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
WidgetLineGaugeDemo.new.run if __FILE__ == $PROGRAM_NAME
|
|
@@ -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
|
+

|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
|
+
require "ratatui_ruby"
|
|
8
|
+
require "faker" # Use Faker for large, realistic datasets
|
|
9
|
+
|
|
10
|
+
# Demonstrates a selectable list of items with interactive attribute cycling.
|
|
11
|
+
#
|
|
12
|
+
# Users need to browse and select from collections of data. Lists are fundamental to terminal interfaces, but managing selection state, scrolling, and styling can be complex.
|
|
13
|
+
#
|
|
14
|
+
# This demo showcases the <tt>List</tt> widget. It provides an interactive playground where you can cycle through different configurations, styles, and behaviors in real-time.
|
|
15
|
+
#
|
|
16
|
+
# Use it to understand how to implement menus, file browsers, or any selectable collection of items.
|
|
17
|
+
#
|
|
18
|
+
# === Examples
|
|
19
|
+
#
|
|
20
|
+
# Run the demo from the terminal:
|
|
21
|
+
#
|
|
22
|
+
# ruby examples/widget_list_demo/app.rb
|
|
23
|
+
#
|
|
24
|
+
# rdoc-image:/doc/images/widget_list_demo.png
|
|
25
|
+
class WidgetListDemo
|
|
26
|
+
# Initializes the demo with example data and default configuration.
|
|
27
|
+
def initialize
|
|
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
|
|
31
|
+
|
|
32
|
+
@item_sets = [
|
|
33
|
+
{
|
|
34
|
+
name: "Programming",
|
|
35
|
+
items: [
|
|
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()
|
|
40
|
+
"Go",
|
|
41
|
+
"C++",
|
|
42
|
+
"C#",
|
|
43
|
+
"Java",
|
|
44
|
+
"Kotlin",
|
|
45
|
+
"Swift",
|
|
46
|
+
"Objective-C",
|
|
47
|
+
"PHP",
|
|
48
|
+
"TypeScript",
|
|
49
|
+
"Perl",
|
|
50
|
+
"Lua",
|
|
51
|
+
"R",
|
|
52
|
+
"Scala",
|
|
53
|
+
"Haskell",
|
|
54
|
+
"Elixir",
|
|
55
|
+
"Clojure",
|
|
56
|
+
"Groovy",
|
|
57
|
+
"Closure",
|
|
58
|
+
"VB.NET",
|
|
59
|
+
"F#",
|
|
60
|
+
"Erlang",
|
|
61
|
+
"Lisp",
|
|
62
|
+
"Scheme",
|
|
63
|
+
"Prolog",
|
|
64
|
+
"Fortran",
|
|
65
|
+
"COBOL",
|
|
66
|
+
"Pascal",
|
|
67
|
+
"Delphi",
|
|
68
|
+
"Ada",
|
|
69
|
+
"Bash",
|
|
70
|
+
"Sh",
|
|
71
|
+
"Tcl",
|
|
72
|
+
"Awk",
|
|
73
|
+
"sed",
|
|
74
|
+
"Vim Script",
|
|
75
|
+
"PowerShell",
|
|
76
|
+
"Batch",
|
|
77
|
+
"Assembly",
|
|
78
|
+
"Wasm",
|
|
79
|
+
"WebAssembly",
|
|
80
|
+
"Julia",
|
|
81
|
+
"Matlab",
|
|
82
|
+
"Octave",
|
|
83
|
+
"BASIC",
|
|
84
|
+
],
|
|
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
|
+
},
|
|
104
|
+
]
|
|
105
|
+
@item_set_index = 0
|
|
106
|
+
|
|
107
|
+
@highlight_symbol_names = [">> ", "▶ ", "→ ", "• ", "★ "]
|
|
108
|
+
@highlight_symbol_index = 0
|
|
109
|
+
|
|
110
|
+
@direction_configs = [
|
|
111
|
+
{ name: "Top to Bottom", direction: :top_to_bottom },
|
|
112
|
+
{ name: "Bottom to Top", direction: :bottom_to_top },
|
|
113
|
+
]
|
|
114
|
+
@direction_index = 0
|
|
115
|
+
|
|
116
|
+
@highlight_spacing_configs = [
|
|
117
|
+
{ name: "When Selected", spacing: :when_selected },
|
|
118
|
+
{ name: "Always", spacing: :always },
|
|
119
|
+
{ name: "Never", spacing: :never },
|
|
120
|
+
]
|
|
121
|
+
@highlight_spacing_index = 1
|
|
122
|
+
|
|
123
|
+
@repeat_modes = [
|
|
124
|
+
{ name: "Off", repeat: false },
|
|
125
|
+
{ name: "On", repeat: true },
|
|
126
|
+
]
|
|
127
|
+
@repeat_index = 0
|
|
128
|
+
|
|
129
|
+
@scroll_padding_configs = [
|
|
130
|
+
{ name: "None", padding: nil },
|
|
131
|
+
{ name: "1 item", padding: 1 },
|
|
132
|
+
{ name: "2 items", padding: 2 },
|
|
133
|
+
]
|
|
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
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Runs the demo application.
|
|
146
|
+
#
|
|
147
|
+
# This method enters the terminal alternate screen, starts the main loop, and handles cleanup on exit.
|
|
148
|
+
def run
|
|
149
|
+
RatatuiRuby.run do |tui|
|
|
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
|
+
|
|
187
|
+
# Initialize styles that require @tui
|
|
188
|
+
@highlight_styles = [
|
|
189
|
+
{ name: "Blue on White Bold", style: @tui.style(fg: :blue, bg: :white, modifiers: [:bold]) },
|
|
190
|
+
{ name: "Blue Bold", style: @tui.style(fg: :blue, modifiers: [:bold]) },
|
|
191
|
+
{ name: "Yellow on Black", style: @tui.style(fg: :yellow, bg: :black) },
|
|
192
|
+
{ name: "Green Italic", style: @tui.style(fg: :green, modifiers: [:italic]) },
|
|
193
|
+
{ name: "White Reversed", style: @tui.style(fg: :white, modifiers: [:reversed]) },
|
|
194
|
+
{ name: "Cyan Bold", style: @tui.style(fg: :cyan, modifiers: [:bold]) },
|
|
195
|
+
]
|
|
196
|
+
@highlight_style_index = 0
|
|
197
|
+
|
|
198
|
+
@base_styles = [
|
|
199
|
+
{ name: "None", style: nil },
|
|
200
|
+
{ name: "Dark Gray", style: @tui.style(fg: :dark_gray) },
|
|
201
|
+
{ name: "White on Black", style: @tui.style(fg: :white, bg: :black) },
|
|
202
|
+
]
|
|
203
|
+
@base_style_index = 0
|
|
204
|
+
|
|
205
|
+
@hotkey_style = @tui.style(modifiers: [:bold, :underlined])
|
|
206
|
+
|
|
207
|
+
loop do
|
|
208
|
+
render
|
|
209
|
+
break if handle_input == :quit
|
|
210
|
+
|
|
211
|
+
sleep 0.05
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# :nodoc:
|
|
217
|
+
private def render
|
|
218
|
+
items = @item_sets[@item_set_index][:items]
|
|
219
|
+
direction_config = @direction_configs[@direction_index]
|
|
220
|
+
spacing_config = @highlight_spacing_configs[@highlight_spacing_index]
|
|
221
|
+
repeat_config = @repeat_modes[@repeat_index]
|
|
222
|
+
highlight_style_config = @highlight_styles[@highlight_style_index]
|
|
223
|
+
highlight_symbol = @highlight_symbol_names[@highlight_symbol_index]
|
|
224
|
+
base_style_config = @base_styles[@base_style_index]
|
|
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
|
|
233
|
+
|
|
234
|
+
@tui.draw do |frame|
|
|
235
|
+
# Split into main content and control panel
|
|
236
|
+
main_area, control_area = @tui.layout_split(
|
|
237
|
+
frame.area,
|
|
238
|
+
direction: :vertical,
|
|
239
|
+
constraints: [
|
|
240
|
+
@tui.constraint_fill(1),
|
|
241
|
+
@tui.constraint_length(8),
|
|
242
|
+
]
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
# Split main content into title and list
|
|
246
|
+
title_area, list_area = @tui.layout_split(
|
|
247
|
+
main_area,
|
|
248
|
+
direction: :vertical,
|
|
249
|
+
constraints: [
|
|
250
|
+
@tui.constraint_length(1),
|
|
251
|
+
@tui.constraint_fill(1),
|
|
252
|
+
]
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# Render title
|
|
256
|
+
title = @tui.paragraph(text: "List Widget Demo - Interactive Attribute Cycling")
|
|
257
|
+
frame.render_widget(title, title_area)
|
|
258
|
+
|
|
259
|
+
# Render list
|
|
260
|
+
list = @tui.list(
|
|
261
|
+
items:,
|
|
262
|
+
selected_index: effective_selection,
|
|
263
|
+
offset: effective_offset,
|
|
264
|
+
style: base_style_config[:style],
|
|
265
|
+
highlight_style: highlight_style_config[:style],
|
|
266
|
+
highlight_symbol:,
|
|
267
|
+
repeat_highlight_symbol: repeat_config[:repeat],
|
|
268
|
+
highlight_spacing: spacing_config[:spacing],
|
|
269
|
+
direction: direction_config[:direction],
|
|
270
|
+
scroll_padding: scroll_padding_config[:padding],
|
|
271
|
+
block: @tui.block(
|
|
272
|
+
title: "#{@item_sets[@item_set_index][:name]} | Sel: #{selection_label} | Offset: #{offset_label}",
|
|
273
|
+
borders: [:all]
|
|
274
|
+
)
|
|
275
|
+
)
|
|
276
|
+
frame.render_widget(list, list_area)
|
|
277
|
+
|
|
278
|
+
# Render control panel
|
|
279
|
+
control_panel = @tui.block(
|
|
280
|
+
title: "Controls",
|
|
281
|
+
borders: [:all],
|
|
282
|
+
children: [
|
|
283
|
+
@tui.paragraph(
|
|
284
|
+
text: [
|
|
285
|
+
@tui.text_line(spans: [
|
|
286
|
+
@tui.text_span(content: "i", style: @hotkey_style),
|
|
287
|
+
@tui.text_span(content: ": Items "),
|
|
288
|
+
@tui.text_span(content: "↑/↓", style: @hotkey_style),
|
|
289
|
+
@tui.text_span(content: ": Navigate "),
|
|
290
|
+
@tui.text_span(content: "x", style: @hotkey_style),
|
|
291
|
+
@tui.text_span(content: ": Select "),
|
|
292
|
+
@tui.text_span(content: "h", style: @hotkey_style),
|
|
293
|
+
@tui.text_span(content: ": Highlight (#{highlight_style_config[:name]})"),
|
|
294
|
+
]),
|
|
295
|
+
@tui.text_line(spans: [
|
|
296
|
+
@tui.text_span(content: "y", style: @hotkey_style),
|
|
297
|
+
@tui.text_span(content: ": Symbol (#{highlight_symbol}) "),
|
|
298
|
+
@tui.text_span(content: "d", style: @hotkey_style),
|
|
299
|
+
@tui.text_span(content: ": Direction (#{direction_config[:name]})"),
|
|
300
|
+
]),
|
|
301
|
+
@tui.text_line(spans: [
|
|
302
|
+
@tui.text_span(content: "s", style: @hotkey_style),
|
|
303
|
+
@tui.text_span(content: ": Spacing (#{spacing_config[:name]}) "),
|
|
304
|
+
@tui.text_span(content: "p", style: @hotkey_style),
|
|
305
|
+
@tui.text_span(content: ": Scroll Padding (#{scroll_padding_config[:name]})"),
|
|
306
|
+
]),
|
|
307
|
+
@tui.text_line(spans: [
|
|
308
|
+
@tui.text_span(content: "b", style: @hotkey_style),
|
|
309
|
+
@tui.text_span(content: ": Base (#{base_style_config[:name]}) "),
|
|
310
|
+
@tui.text_span(content: "r", style: @hotkey_style),
|
|
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]}) "),
|
|
316
|
+
@tui.text_span(content: "q", style: @hotkey_style),
|
|
317
|
+
@tui.text_span(content: ": Quit"),
|
|
318
|
+
]),
|
|
319
|
+
]
|
|
320
|
+
),
|
|
321
|
+
]
|
|
322
|
+
)
|
|
323
|
+
frame.render_widget(control_panel, control_area)
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# :nodoc:
|
|
328
|
+
private def handle_input
|
|
329
|
+
case @tui.poll_event
|
|
330
|
+
in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
|
|
331
|
+
:quit
|
|
332
|
+
in type: :key, code: "i"
|
|
333
|
+
@item_set_index = (@item_set_index + 1) % @item_sets.size
|
|
334
|
+
@selected_index = nil
|
|
335
|
+
in type: :key, code: "up"
|
|
336
|
+
items = @item_sets[@item_set_index][:items]
|
|
337
|
+
@selected_index = (@selected_index || 0) - 1
|
|
338
|
+
@selected_index = items.size - 1 if @selected_index.negative?
|
|
339
|
+
in type: :key, code: "down"
|
|
340
|
+
items = @item_sets[@item_set_index][:items]
|
|
341
|
+
@selected_index = ((@selected_index || -1) + 1) % items.size
|
|
342
|
+
in type: :key, code: "x"
|
|
343
|
+
@selected_index = @selected_index.nil? ? 0 : nil
|
|
344
|
+
in type: :key, code: "h"
|
|
345
|
+
@highlight_style_index = (@highlight_style_index + 1) % @highlight_styles.size
|
|
346
|
+
in type: :key, code: "y"
|
|
347
|
+
@highlight_symbol_index = (@highlight_symbol_index + 1) % @highlight_symbol_names.size
|
|
348
|
+
in type: :key, code: "d"
|
|
349
|
+
@direction_index = (@direction_index + 1) % @direction_configs.size
|
|
350
|
+
in type: :key, code: "s"
|
|
351
|
+
@highlight_spacing_index = (@highlight_spacing_index + 1) % @highlight_spacing_configs.size
|
|
352
|
+
in type: :key, code: "b"
|
|
353
|
+
@base_style_index = (@base_style_index + 1) % @base_styles.size
|
|
354
|
+
in type: :key, code: "r"
|
|
355
|
+
@repeat_index = (@repeat_index + 1) % @repeat_modes.size
|
|
356
|
+
in type: :key, code: "p"
|
|
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
|
|
360
|
+
else
|
|
361
|
+
nil
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
WidgetListDemo.new.run if __FILE__ == $PROGRAM_NAME
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Canvas Widget Example
|
|
7
|
+
|
|
8
|
+
Demonstrates drawing custom graphics and maps using the standard Braille and Block patterns.
|
|
9
|
+
|
|
10
|
+
Standard widgets are great for text, but sometimes you need to draw. The `Canvas` widget gives you a high-resolution coordinate system (x, y) to render shapes, lines, and data visualizations that go beyond the grid.
|
|
11
|
+
|
|
12
|
+
## Features Demonstrated
|
|
13
|
+
|
|
14
|
+
- **High-Resolution Drawing**: Using Braille patterns (`⣿`) to effectively double the vertical and horizontal resolution of the terminal.
|
|
15
|
+
- **Layers**: Drawing multiple shapes (Map, Circles, Lines) in a specific order.
|
|
16
|
+
- **Animation**: Updating coordinates in a loop to create smooth motion.
|
|
17
|
+
- **World Map**: Using the built-in `Map` shape for geographic data.
|
|
18
|
+
|
|
19
|
+
## Hotkeys
|
|
20
|
+
|
|
21
|
+
- **b**: Cycle Background Color (`background_color`)
|
|
22
|
+
- **m**: Cycle Marker Type (`marker`)
|
|
23
|
+
- **l**: Toggle Labels (modifies `shapes`)
|
|
24
|
+
- **q**: Quit
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
ruby examples/widget_map_demo/app.rb
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Learning Outcomes
|
|
33
|
+
|
|
34
|
+
Use this example if you need to...
|
|
35
|
+
- Render geographic data (World, USA, Europe).
|
|
36
|
+
- Overlay custom labels and markers on a map.
|
|
37
|
+
- Animate visual elements on top of a static background.
|
|
38
|
+
|
|
39
|
+

|