Class: Tuile::Component::IntegerField
- Inherits:
-
Component
- Object
- Component
- Tuile::Component::IntegerField
- Includes:
- HasContent, HasValue
- Defined in:
- lib/tuile/component/integer_field.rb,
sig/tuile.rbs
Overview
A single-line field whose #value is an Integer (or nil when empty).
The user may type only 0–9 and a single leading -; anything else is
silently rejected without moving the caret. Up/Down step the value by one
(an empty field counting as 0). An empty or otherwise un-parseable
buffer reads back as nil:
field = Component::IntegerField.new
field.on_value_change = ->(n) { puts n.inspect } # Integer or nil, per change
field.value = 42 # field shows "42"
field.value # => 42
field.clear # empties it; value => nil
Like ComboBox, it composes a TextField (its single HasContent
child) rather than subclassing one — its face carries only the typed
HasValue value seam, never the widget's String-typed text. It's the
same wrapper shape as ComboBox minus the dropdown: a digit-filtered text
field re-exposed as a typed input. Give it a single-row #rect.
The value is a derived parse of the buffer
#value is Integer(buffer, 10) (or nil), recomputed on read — the
buffer is the single source of truth, #value= just writes it. So "-"
alone and "" both read as nil, and on_value_change fires eagerly
once per real value change: typing 0→7 in "07" shifts the buffer
but not the value (7), so it does not fire. No normalization — a typed
"007" stays "007" on screen though its value is 7.
min/max, a + sign, and thousands separators are deliberately out of
scope (range and formatting are a forms concern).
UI-thread-confined, like every component (see Screen).
Instance Attribute Summary
Attributes included from HasValue
Attributes included from HasContent
Instance Method Summary collapse
-
#accepts?(char) ⇒ Boolean
A digit anywhere, or a
-only as the very first character. -
#clear ⇒ void
Resets #value to #empty_value.
-
#cursor_position ⇒ Point?
@return — the field's caret (the hardware cursor is delegated to the inner field).
-
#empty? ⇒ Boolean
@return — true iff #value equals #empty_value.
-
#empty_value ⇒ void
nil, not"": an integer field with no parseable number is empty. -
#field_key(key) ⇒ Boolean
The field's key interceptor, consulted before the field acts on the key: Up/Down step the value; a printable key the field mustn't accept is swallowed (so a rejected key never moves the caret); everything else — digits, the leading sign, and all editing/navigation keys — falls through.
-
#fire_if_changed ⇒ void
Re-emits HasValue#on_value_change with the freshly-parsed #value, but only when it differs from the last one fired — so a buffer edit that leaves the value unchanged (
"7"→"07") stays silent. -
#focusable? ⇒ Boolean
Input fields are focusable by default (overrides #focusable?); a read-only display field could override back to
false. -
#handle_mouse ⇒ void
@param
event. -
#initialize ⇒ IntegerField
constructor
A new instance of IntegerField.
-
#layout(field) ⇒ void
Places the wrapped field across the whole rect (HasContent hook).
-
#on_enter ⇒ Proc, ...
Fired when ENTER is pressed in the field; see TextField#on_enter.
-
#on_enter=(callback) ⇒ void
@param
callback. - #on_focus ⇒ void
-
#rect= ⇒ void
@param
rect. -
#step(delta) ⇒ void
Nudges #value by
delta, treating an empty/un-parseable field as0. -
#value ⇒ Integer?
@return — the parsed buffer;
nilwhen empty or not a valid integer (e.g. a lone"-"). -
#value=(new_value) ⇒ void
Writes
new_valueinto the buffer and parks the caret at its end; fires HasValue#on_value_change only if the value actually changed.
Constructor Details
#initialize ⇒ IntegerField
Returns a new instance of IntegerField.
39 40 41 42 43 44 45 46 |
# File 'lib/tuile/component/integer_field.rb', line 39 def initialize super() @last_value = nil field = TextField.new field.on_change = ->(_text) { fire_if_changed } field.on_key = method(:field_key) self.content = field end |
Instance Method Details
#accepts?(char) ⇒ Boolean
A digit anywhere, or a - only as the very first character.
@param char — a single printable character.
116 117 118 119 120 |
# File 'lib/tuile/component/integer_field.rb', line 116 def accepts?(char) return true if char.match?(/\A[0-9]\z/) char == "-" && content.caret.zero? && !content.text.start_with?("-") end |
#clear ⇒ void
This method returns an undefined value.
Resets #value to #empty_value.
4007 |
# File 'sig/tuile.rbs', line 4007
def clear: () -> void
|
#cursor_position ⇒ Point?
@return — the field's caret (the hardware cursor is delegated to the inner field).
71 |
# File 'lib/tuile/component/integer_field.rb', line 71 def cursor_position = content.cursor_position |
#empty? ⇒ Boolean
@return — true iff #value equals #empty_value.
4004 |
# File 'sig/tuile.rbs', line 4004
def empty?: () -> bool
|
#empty_value ⇒ void
This method returns an undefined value.
nil, not "": an integer field with no parseable number is empty.
67 |
# File 'lib/tuile/component/integer_field.rb', line 67 def empty_value = nil |
#field_key(key) ⇒ Boolean
The field's key interceptor, consulted before the field acts on the key: Up/Down step the value; a printable key the field mustn't accept is swallowed (so a rejected key never moves the caret); everything else — digits, the leading sign, and all editing/navigation keys — falls through.
@param key
@return — true to consume the key.
99 100 101 102 103 104 105 106 |
# File 'lib/tuile/component/integer_field.rb', line 99 def field_key(key) case key when Keys::UP_ARROW then step(1) when Keys::DOWN_ARROW then step(-1) else return Keys.printable?(key) && !accepts?(key) end true end |
#fire_if_changed ⇒ void
This method returns an undefined value.
Re-emits HasValue#on_value_change with the freshly-parsed #value, but only
when it differs from the last one fired — so a buffer edit that leaves
the value unchanged ("7"→"07") stays silent.
126 127 128 129 130 131 132 |
# File 'lib/tuile/component/integer_field.rb', line 126 def fire_if_changed v = value return if v == @last_value @last_value = v on_value_change&.call(v) end |
#focusable? ⇒ Boolean
Input fields are focusable by default (overrides Tuile::Component#focusable?);
a read-only display field could override back to false. Only
focusable? lives here — tab_stop? diverges between leaf fields and
composing wrappers, so it stays per-class (DECISIONS.md
D-integer-field).
4014 |
# File 'sig/tuile.rbs', line 4014
def focusable?: () -> bool
|
#handle_mouse ⇒ void
This method returns an undefined value.
@param event
4017 |
# File 'sig/tuile.rbs', line 4017
def handle_mouse: (MouseEvent event) -> void
|
#layout(field) ⇒ void
This method returns an undefined value.
Places the wrapped field across the whole rect (HasContent hook).
@param field
88 |
# File 'lib/tuile/component/integer_field.rb', line 88 def layout(field) = (field.rect = rect) |
#on_enter ⇒ Proc, ...
Fired when ENTER is pressed in the field; see TextField#on_enter.
@return — no-arg callable, or nil.
75 |
# File 'lib/tuile/component/integer_field.rb', line 75 def on_enter = content.on_enter |
#on_enter=(callback) ⇒ void
This method returns an undefined value.
@param callback
79 80 81 |
# File 'lib/tuile/component/integer_field.rb', line 79 def on_enter=(callback) content.on_enter = callback end |
#on_focus ⇒ void
This method returns an undefined value.
4022 |
# File 'sig/tuile.rbs', line 4022
def on_focus: () -> void
|
#rect= ⇒ void
This method returns an undefined value.
@param rect
4020 |
# File 'sig/tuile.rbs', line 4020
def rect=: (Rect rect) -> void
|
#step(delta) ⇒ void
This method returns an undefined value.
Nudges #value by delta, treating an empty/un-parseable field as 0.
@param delta
111 |
# File 'lib/tuile/component/integer_field.rb', line 111 def step(delta) = (self.value = (value || 0) + delta) |
#value ⇒ Integer?
@return — the parsed buffer; nil when empty or not a
valid integer (e.g. a lone "-").
50 51 52 53 54 |
# File 'lib/tuile/component/integer_field.rb', line 50 def value Integer(content.text, 10) rescue ArgumentError nil end |
#value=(new_value) ⇒ void
This method returns an undefined value.
Writes new_value into the buffer and parks the caret at its end; fires
HasValue#on_value_change only if the value actually changed.
@param new_value — nil empties the field.
60 61 62 63 |
# File 'lib/tuile/component/integer_field.rb', line 60 def value=(new_value) content.text = new_value.nil? ? "" : new_value.to_s content.caret = content.text.length end |