class HexaPDF::Type::AcroForm::TextField

See: PDF2.0 s12.7.5.3
:rich_text
The field is a rich text field.
numbers which always have the same length.
set). This is useful, for example, when entering things like social security
:comb
The field is divided into /MaxLen equally spaced positions (so /MaxLen needs to be
field is full.
annotation rectangle. This means that no more text can be entered once the
vertically for multiline fields) to accomodate more text than fits into the
:do_not_scroll
The text field should not scroll (horizontally for single-line fields and
:do_not_spell_check
The text should not be spell-checked.
the path to a file.
:file_select
The text field represents a file selection control where the input text is
application to not echo the input text and to not store it in the PDF file.
:password
The field is a password field. This changes the behaviour of the PDF reader
:multiline

If set, the text field may contain multiple lines.
== Type Specific Field Flags
the existing space into /MaxLen equally spaced positions.
A special type of single-line text field is the comb text field. This type of field divides
may be restricted to a single line or can span multiple lines.
AcroForm text fields provide a box or space to fill-in data entered from keyboard. The text

def comb_text_field?

Returns +true+ if this field is a comb text field.
def comb_text_field?
  flagged?(:comb) && !(flagged?(:file_select) || flagged?(:multiline) || flagged?(:password))
end

def concrete_field_type

:rich_text_field.
:multiline_text_field, :password_field, :file_select_field, :comb_text_field or
Returns the concrete text field type, either :single_line_text_field,
def concrete_field_type
  if flagged?(:multiline)
    :multiline_text_field
  elsif flagged?(:password)
    :password_field
  elsif flagged?(:file_select)
    :file_select_field
  elsif flagged?(:comb)
    :comb_text_field
  elsif flagged?(:rich_text)
    :rich_text_field
  else
    :single_line_text_field
  end
end

def create_appearances(force: false)

By setting +force+ to +true+ the creation of the appearances can be forced.

invocations.
Note that no new appearances are created if the field value hasn't changed between

For information on how this is done see AppearanceGenerator.

Creates appropriate appearances for all widgets.
def create_appearances(force: false)
  current_value = field_value
  appearance_generator_class = document.config.constantize('acro_form.appearance_generator')
  each_widget do |widget|
    is_cached = widget.cached?(:last_value)
    unless force
      if is_cached && widget.cache(:last_value) == current_value
        next
      elsif !is_cached && widget.appearance?
        widget.cache(:last_value, current_value, update: true)
        next
      end
    end
    widget.cache(:last_value, current_value, update: true)
    appearance_generator_class.new(widget).create_text_appearances
  end
end

def default_field_value

See: #field_value

Returns the default field value.
def default_field_value
  self[:DV].kind_of?(String) ? self[:DV] : self[:DV].stream
end

def default_field_value=(str)

See: #field_value=

Sets the default field value.
def default_field_value=(str)
  self[:DV] = str
end

def field_value

stored as stream! So always use #field_value= to set the field value.
Note that modifying the returned value *might not* modify the text contents in case it is

Returns the field value, i.e. the text contents of the field, or +nil+ if no value is set.
def field_value
  return unless value[:V]
  self[:V].kind_of?(String) ? self[:V] : self[:V].stream
end

def field_value=(str)

spaces.
Note that for single line text fields, all whitespace characters are changed to simple

Sets the field value, i.e. the text contents of the field, to the given string.
def field_value=(str)
  if flagged?(:password)
    raise HexaPDF::Error, "Storing a field value for a password field is not allowed"
  elsif comb_text_field? && !key?(:MaxLen)
    raise HexaPDF::Error, "A comb text field need a valid /MaxLen value"
  end
  str = str.gsub(/[[:space:]]/, ' ') if str && concrete_field_type == :single_line_text_field
  if key?(:MaxLen) && str && str.length > self[:MaxLen]
    raise HexaPDF::Error, "Value exceeds maximum allowed length of #{self[:MaxLen]}"
  end
  self[:V] = str
  update_widgets
end

def file_select_field?

Returns +true+ if this field is a file select field.
def file_select_field?
  flagged?(:file_select) && !(flagged?(:password) || flagged?(:multiline) || flagged?(:comb))
end

def initialize_as_comb_text_field

doesn't completely reset the object.
This method should only be called directly after creating a new text field because it

Initializes the text field to be a comb text field.
def initialize_as_comb_text_field
  flag(:comb)
  unflag(:file_select, :multiline, :password)
end

def initialize_as_file_select_field

doesn't completely reset the object.
This method should only be called directly after creating a new text field because it

Initializes the text field to be a file select field.
def initialize_as_file_select_field
  flag(:file_select)
  unflag(:comb, :multiline, :password)
end

def initialize_as_multiline_text_field

doesn't completely reset the object.
This method should only be called directly after creating a new text field because it

Initializes the text field to be a multiline text field.
def initialize_as_multiline_text_field
  flag(:multiline)
  unflag(:file_select, :comb, :password)
end

def initialize_as_password_field

doesn't completely reset the object.
This method should only be called directly after creating a new text field because it

Initializes the text field to be a password field.
def initialize_as_password_field
  delete(:V)
  flag(:password)
  unflag(:comb, :multiline, :file_select)
end

def multiline_text_field?

Returns +true+ if this field is a multiline text field.
def multiline_text_field?
  flagged?(:multiline) && !(flagged?(:file_select) || flagged?(:comb) || flagged?(:password))
end

def password_field?

Returns +true+ if this field is a password field.
def password_field?
  flagged?(:password) && !(flagged?(:file_select) || flagged?(:multiline) || flagged?(:comb))
end

def perform_validation #:nodoc:

:nodoc:
def perform_validation #:nodoc:
  if field_type != :Tx
    yield("Field /FT of AcroForm text field has to be :Tx", true)
    self[:FT] = :Tx
  end
  super
  if self[:V] && !(self[:V].kind_of?(String) || self[:V].kind_of?(HexaPDF::Stream))
    yield("Text field doesn't contain text but #{self[:V].class} object")
    return
  end
  if (max_len = self[:MaxLen]) && field_value && field_value.length > max_len
    yield("Text contents of field '#{full_field_name}' is too long")
  end
  if comb_text_field? && !max_len
    yield("Comb text field needs a value for /MaxLen")
  end
end

def update_widgets

Updates the widgets so that they reflect the current field value.
def update_widgets
  create_appearances(force: true)
end