Class: Potty::Widgets::TextInput

Inherits:
Base
  • Object
show all
Defined in:
lib/potty/widgets/text_input.rb

Overview

Single-line editable text field. Shows a block cursor when focused, a dim placeholder when empty and unfocused, and scrolls horizontally when the text outgrows the field.

Emits :change(text) on every edit. ASCII input only for now (matches the rest of the framework); UTF-8 entry would need multibyte getch.

Instance Attribute Summary collapse

Attributes inherited from Base

#app, #focused, #parent, #rect

Instance Method Summary collapse

Methods inherited from Base

#activate, #blur, #deactivate, #focus, #handle_escape, #hide, #layout, #on_blur, #on_focus, #on_layout, #show, #theme, #tick, #visible=, #visible?

Methods included from Events

#emit, #listeners?, #off, #on

Constructor Details

#initialize(app, text: '', placeholder: '', max_length: nil, on_change: nil) ⇒ TextInput

Returns a new instance of TextInput.



19
20
21
22
23
24
25
26
27
# File 'lib/potty/widgets/text_input.rb', line 19

def initialize(app, text: '', placeholder: '', max_length: nil, on_change: nil)
  super(app)
  @text = text.dup
  @placeholder = placeholder
  @max_length = max_length
  @on_change = on_change
  @cursor = @text.length
  @scroll = 0
end

Instance Attribute Details

#max_lengthObject

Returns the value of attribute max_length.



17
18
19
# File 'lib/potty/widgets/text_input.rb', line 17

def max_length
  @max_length
end

#on_changeObject

Returns the value of attribute on_change.



17
18
19
# File 'lib/potty/widgets/text_input.rb', line 17

def on_change
  @on_change
end

#placeholderObject

Returns the value of attribute placeholder.



17
18
19
# File 'lib/potty/widgets/text_input.rb', line 17

def placeholder
  @placeholder
end

#textObject

Returns the value of attribute text.



16
17
18
# File 'lib/potty/widgets/text_input.rb', line 16

def text
  @text
end

Instance Method Details

#can_focus?Boolean

Returns:

  • (Boolean)


29
30
31
# File 'lib/potty/widgets/text_input.rb', line 29

def can_focus?
  true
end

#handle_key(ch) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/potty/widgets/text_input.rb', line 43

def handle_key(ch)
  case ch
  when Keys::LEFT
    @cursor = [@cursor - 1, 0].max
  when Keys::RIGHT
    @cursor = [@cursor + 1, @text.length].min
  when Keys::HOME, Keys::CTRL_A
    @cursor = 0
  when Keys::END_, Keys::CTRL_E
    @cursor = @text.length
  when Keys::DEL_ASCII, Keys::CTRL_H, Keys::BACKSPACE
    backspace
  when Keys::DELETE, Keys::CTRL_D
    delete_forward
  when Keys::SPACE..(Keys::DEL_ASCII - 1)
    insert(ch.chr)
  else
    return false
  end
  true
end

#preferred_height(_width) ⇒ Object



39
40
41
# File 'lib/potty/widgets/text_input.rb', line 39

def preferred_height(_width)
  1
end

#render(window) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/potty/widgets/text_input.rb', line 65

def render(window)
  return unless @visible && @rect

  width = @rect.width
  adjust_scroll(width)

  if @text.empty? && !@focused
    window.setpos(@rect.y, @rect.x)
    window.attron(theme[:dim]) do
      window.addstr(@placeholder.to_s[0, width].to_s.ljust(width))
    end
    return
  end

  visible = (@text[@scroll, width] || '').ljust(width)
  window.setpos(@rect.y, @rect.x)
  window.attron(theme[:normal]) { window.addstr(visible) }

  return unless @focused

  # Block cursor: reverse-video the cell under the caret.
  col = @cursor - @scroll
  return if col.negative? || col >= width

  char_under = @text[@cursor] || ' '
  window.setpos(@rect.y, @rect.x + col)
  window.attron(theme[:normal] | ::Curses::A_REVERSE) do
    window.addstr(char_under)
  end
end