Class: Tuile::Component::TextInput
- Inherits:
-
Tuile::Component
- Object
- Tuile::Component
- Tuile::Component::TextInput
- Defined in:
- lib/tuile/component/text_input.rb
Overview
Abstract base for editable text components (TextField, TextArea).
Holds the shared state — a mutable #text buffer, a #caret index, #on_change and #on_escape callbacks — and the keyboard machinery that single-line and multi-line inputs both need: ESC handling, LEFT/RIGHT caret movement, CTRL+LEFT/CTRL+RIGHT word jumps, and the ‘focusable?`/`tab_stop?` flags.
Subclasses implement the layout-specific pieces (#cursor_position, #repaint) and add their own keys (HOME/END, ENTER, UP/DOWN, printable insertion) by overriding the protected #handle_text_input_key hook — ‘super` falls through to the common navigation handling.
The mutation pipeline is a template method: #text= and #caret= detect no-ops, mutate state, fire #on_change, and invalidate. Subclasses inject their own behavior via two protected hooks:
Instance Attribute Summary collapse
-
#caret ⇒ Integer
Caret index in ‘0..text.length`.
-
#on_change ⇒ Proc, ...
Optional callback fired whenever #text changes.
-
#on_escape ⇒ Proc, ...
Callback fired when ESC is pressed.
-
#on_key ⇒ Proc, ...
Optional interceptor consulted before the input’s own key handling.
-
#text ⇒ String
Current text contents.
Attributes inherited from Tuile::Component
#content_size, #key_shortcut, #on_theme_changed, #parent, #rect
Instance Method Summary collapse
-
#empty? ⇒ Boolean
True iff #text is the empty string.
- #focusable? ⇒ Boolean
-
#handle_key(key) ⇒ Boolean
Handles a key.
-
#initialize ⇒ TextInput
constructor
A new instance of TextInput.
- #tab_stop? ⇒ Boolean
Methods inherited from Tuile::Component
#active=, #active?, #attached?, #children, #cursor_position, #depth, #find_shortcut_component, #focus, #handle_mouse, #keyboard_hint, #on_child_content_size_changed, #on_child_removed, #on_focus, #on_tree, #popup_max_height, #popup_min_height, #repaint, #root, #screen
Constructor Details
#initialize ⇒ TextInput
Returns a new instance of TextInput.
29 30 31 32 33 34 35 36 |
# File 'lib/tuile/component/text_input.rb', line 29 def initialize super @text = +"" @caret = 0 @on_change = nil @on_key = nil @on_escape = method(:default_on_escape) end |
Instance Attribute Details
#caret ⇒ Integer
Returns caret index in ‘0..text.length`.
45 46 47 |
# File 'lib/tuile/component/text_input.rb', line 45 def caret @caret end |
#on_change ⇒ Proc, ...
51 52 53 |
# File 'lib/tuile/component/text_input.rb', line 51 def on_change @on_change end |
#on_escape ⇒ Proc, ...
Callback fired when ESC is pressed. Defaults to a closure that clears focus (‘screen.focused = nil`) so ESC visibly cancels text entry instead of bubbling to the parent — and, in particular, instead of reaching the screen’s default ESC-to-quit handler. Set to nil to let ESC fall through to the parent again; set to any other callable to replace the default.
73 74 75 |
# File 'lib/tuile/component/text_input.rb', line 73 def on_escape @on_escape end |
#on_key ⇒ Proc, ...
Optional interceptor consulted before the input’s own key handling. Receives the pressed key; return a truthy value to consume it (the input then ignores that key), falsy to let normal editing proceed.
The keyboard analog of #on_change: it lets app code layer behavior onto an input without subclassing. The motivating case is an autocomplete / slash-command overlay (a non-modal Popup): while it is open the interceptor claims Up/Down/Enter/ESC and forwards them to the overlay’s list, but lets ordinary characters fall through so typing keeps editing the field (and #on_change keeps refilling the list).
65 66 67 |
# File 'lib/tuile/component/text_input.rb', line 65 def on_key @on_key end |
#text ⇒ String
Returns current text contents.
39 40 41 |
# File 'lib/tuile/component/text_input.rb', line 39 def text @text end |
Instance Method Details
#empty? ⇒ Boolean
Returns true iff #text is the empty string.
42 |
# File 'lib/tuile/component/text_input.rb', line 42 def empty? = @text.empty? |
#focusable? ⇒ Boolean
75 |
# File 'lib/tuile/component/text_input.rb', line 75 def focusable? = true |
#handle_key(key) ⇒ Boolean
Handles a key. An #on_key interceptor (if set) gets first refusal —a truthy return consumes the key — otherwise it delegates to #handle_text_input_key. Dispatch (ScreenPane#handle_key) only routes keys here when this input is on the focus chain, so there is no Tuile::Component#active? gate.
113 114 115 116 117 |
# File 'lib/tuile/component/text_input.rb', line 113 def handle_key(key) return true if @on_key&.call(key) handle_text_input_key(key) end |
#tab_stop? ⇒ Boolean
77 |
# File 'lib/tuile/component/text_input.rb', line 77 def tab_stop? = true |