A display-only component showing keyboard shortcuts and clipboard feedback.
Users need to know what keys are available. They also need feedback when they copy a color. This component renders the controls section.
Component Contract
-
โrender(tui, frame, area, clipboard:)`: Draws the controls; stores `area`
-
โhandle_event(event) -> nil`: Display-only, always returns nil
-
โtick`: Delegates to clipboard for time-based feedback updates
Example
controls = Controls.new controls.render(tui, frame, area, clipboard: clipboard) controls.tick(clipboard)
Source Code
# frozen_string_literal: true #-- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com> # SPDX-License-Identifier: AGPL-3.0-or-later #++ # A display-only component showing keyboard shortcuts and clipboard feedback. # # Users need to know what keys are available. They also need feedback when # they copy a color. This component renders the controls section. # # === Component Contract # # - `render(tui, frame, area, clipboard:)`: Draws the controls; stores `area` # - `handle_event(event) -> nil`: Display-only, always returns nil # - `tick`: Delegates to clipboard for time-based feedback updates # # === Example # # controls = Controls.new # controls.render(tui, frame, area, clipboard: clipboard) # controls.tick(clipboard) class Controls def initialize @area = nil @hotkey_style = nil end # The cached render area. attr_reader :area # Renders the controls section into the given area. # # Shows keyboard shortcuts and clipboard feedback message if one is active. # # [tui] Session or TUI factory object # [frame] Frame object from RatatuiRuby.draw block # [area] Rect area to draw into # [clipboard] Clipboard object for feedback message # # === Example # # controls.render(tui, frame, control_area, clipboard: clipboard) def render(tui, frame, area, clipboard:) @area = area @hotkey_style ||= tui.style(modifiers: [:bold, :underlined]) widget = build_widget(tui, clipboard) frame.render_widget(widget, area) end # Display-only component; always returns nil. def handle_event(_event) nil end # Delegates tick to the clipboard for time-based updates. # # [clipboard] Clipboard object to tick def tick(clipboard) clipboard.tick end private def build_widget(tui, clipboard) control_lines = [ tui.text_line(spans: [ tui.text_span(content: "a-z/0-9", style: @hotkey_style), tui.text_span(content: ": Type "), tui.text_span(content: "enter", style: @hotkey_style), tui.text_span(content: ": Parse "), tui.text_span(content: "bksp", style: @hotkey_style), tui.text_span(content: ": Erase "), tui.text_span(content: "esc", style: @hotkey_style), tui.text_span(content: ": Quit"), ]), ] unless clipboard.message.empty? control_lines << tui.text_line(spans: [ tui.text_span(content: clipboard.message, style: tui.style(fg: :green, modifiers: [:bold])), ]) end tui.block( title: "Controls", borders: [:all], children: [ tui.paragraph(text: control_lines), ] ) end end