Class: Tuile::Component::TextField

Inherits:
Tuile::Component show all
Defined in:
lib/tuile/component/text_field.rb

Overview

A single-line text input field with hardware-cursor caret.

The field does not scroll. Any keystroke that would make #text longer than ‘rect.width - 1` (the last column is reserved for the caret past the last char) is rejected.

The caret is a logical index in ‘0..text.length`. The hardware cursor is positioned by Screen after each repaint cycle when this component is focused; see #cursor_position.

Instance Attribute Summary collapse

Attributes inherited from Tuile::Component

#key_shortcut, #parent, #rect

Instance Method Summary collapse

Methods inherited from Tuile::Component

#active=, #active?, #attached?, #children, #content_size, #depth, #find_shortcut_component, #focus, #keyboard_hint, #on_child_removed, #on_focus, #on_tree, #root, #screen

Constructor Details

#initializeTextField

Returns a new instance of TextField.



15
16
17
18
19
20
21
22
23
24
# File 'lib/tuile/component/text_field.rb', line 15

def initialize
  super
  @text = +""
  @caret = 0
  @on_escape = nil
  @on_change = nil
  @on_key_up = nil
  @on_key_down = nil
  @on_enter = nil
end

Instance Attribute Details

#caretInteger

Returns caret index in ‘0..text.length`.

Returns:

  • (Integer)

    caret index in ‘0..text.length`.



30
31
32
# File 'lib/tuile/component/text_field.rb', line 30

def caret
  @caret
end

#on_changeProc, ...

Optional callback fired whenever #text changes. Receives the new text as a single argument. Not fired by #caret= (text unchanged) and not fired when a setter is a no-op.

Returns:

  • (Proc, Method, nil)

    one-arg callable, or nil.



42
43
44
# File 'lib/tuile/component/text_field.rb', line 42

def on_change
  @on_change
end

#on_enterProc, ...

Optional callback fired when ENTER is pressed. When set, ENTER is consumed by the field; when nil, ENTER falls through to the parent (default behavior).

Returns:

  • (Proc, Method, nil)

    no-arg callable, or nil.



62
63
64
# File 'lib/tuile/component/text_field.rb', line 62

def on_enter
  @on_enter
end

#on_escapeProc, ...

Optional callback fired when ESC is pressed. When set, ESC is consumed by the field; when nil, ESC falls through to the parent (default behavior).

Returns:

  • (Proc, Method, nil)

    no-arg callable, or nil.



36
37
38
# File 'lib/tuile/component/text_field.rb', line 36

def on_escape
  @on_escape
end

#on_key_downProc, ...

Optional callback fired when the DOWN arrow key is pressed. When set, DOWN is consumed by the field; when nil, DOWN falls through to the parent (default behavior). Only triggered by Keys::DOWN_ARROW, not by ‘j`, since `j` is a printable character inserted into #text.

Returns:

  • (Proc, Method, nil)

    no-arg callable, or nil.



56
57
58
# File 'lib/tuile/component/text_field.rb', line 56

def on_key_down
  @on_key_down
end

#on_key_upProc, ...

Optional callback fired when the UP arrow key is pressed. When set, UP is consumed by the field; when nil, UP falls through to the parent (default behavior). Only triggered by Keys::UP_ARROW, not by ‘k`, since `k` is a printable character inserted into #text.

Returns:

  • (Proc, Method, nil)

    no-arg callable, or nil.



49
50
51
# File 'lib/tuile/component/text_field.rb', line 49

def on_key_up
  @on_key_up
end

#textString

Returns current text contents.

Returns:

  • (String)

    current text contents.



27
28
29
# File 'lib/tuile/component/text_field.rb', line 27

def text
  @text
end

Instance Method Details

#cursor_positionPoint?

Returns:



91
92
93
94
95
# File 'lib/tuile/component/text_field.rb', line 91

def cursor_position
  return nil unless rect.width.positive?

  Point.new(rect.left + @caret, rect.top)
end

#focusable?Boolean

Returns:

  • (Boolean)


88
# File 'lib/tuile/component/text_field.rb', line 88

def focusable? = true

#handle_key(key) ⇒ Boolean

Parameters:

  • key (String)

Returns:

  • (Boolean)


99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/tuile/component/text_field.rb', line 99

def handle_key(key)
  return false unless active?
  return true if super

  case key
  when Keys::LEFT_ARROW then self.caret = @caret - 1
  when Keys::RIGHT_ARROW then self.caret = @caret + 1
  when Keys::HOME then self.caret = 0
  when Keys::END_ then self.caret = @text.length
  when *Keys::BACKSPACES then delete_before_caret
  when Keys::DELETE then delete_at_caret
  when Keys::ESC
    return false if @on_escape.nil?

    @on_escape.call
  when Keys::UP_ARROW
    return false if @on_key_up.nil?

    @on_key_up.call
  when Keys::DOWN_ARROW
    return false if @on_key_down.nil?

    @on_key_down.call
  when Keys::ENTER
    return false if @on_enter.nil?

    @on_enter.call
  else
    return insert(key) if printable?(key)

    return false
  end
  true
end

#handle_mouse(event) ⇒ void

This method returns an undefined value.

Parameters:



136
137
138
139
140
141
# File 'lib/tuile/component/text_field.rb', line 136

def handle_mouse(event)
  super
  return unless event.button == :left && rect.contains?(event.point)

  self.caret = (event.x - rect.left).clamp(0, @text.length)
end

#repaintvoid

This method returns an undefined value.



144
145
146
147
148
149
# File 'lib/tuile/component/text_field.rb', line 144

def repaint
  clear_background
  return if rect.empty?

  screen.print TTY::Cursor.move_to(rect.left, rect.top), @text
end