class HexaPDF::Type::AcroForm::ButtonField

AcroForm button fields represent interactive controls to be used with the mouse.

They are divided into push buttons (things to click on), check boxes and radio buttons. All of these are represented with this class.

To create a push button, check box or radio button field, use the appropriate convenience methods on the main Form instance (HexaPDF::Document#acro_form). By using those methods, everything needed is automatically set up.

Type Specific Field Flags

:no_toggle_to_off

Only used with radio buttons fields. If this flag is set, one button needs to be selected at all times. Otherwise, clicking on the selected button deselects it.

:radio

If this flag is set, the field is a set of radio buttons. Otherwise it is a check box. Additionally, the :pushbutton flag needs to be clear.

:push_button

The field represents a pushbutton without a permanent value.

:radios_in_unison

A group of radio buttons with the same value for the on state will turn on or off in unison.

See: PDF1.7 s12.7.4.2

Constants

FLAGS_BIT_MAPPING

Updated list of field flags.

INHERITABLE_FIELDS

All inheritable dictionary fields for button fields.

Public Instance Methods

check_box?() click to toggle source

Returns true if this button field represents a check box.

# File lib/hexapdf/type/acro_form/button_field.rb, line 120
def check_box?
  !push_button? && !flagged?(:radio)
end
check_box_on_name() click to toggle source

Returns the name (a Symbol) used for setting the check box to the on state.

Defaults to :Yes if no other name could be determined.

# File lib/hexapdf/type/acro_form/button_field.rb, line 185
def check_box_on_name
  each_widget.to_a.first&.appearance_dict&.normal_appearance&.value&.each_key&.
    find {|key| key != :Off } || :Yes
end
concrete_field_type() click to toggle source

Returns the concrete button field type, either :push_button, :check_box or :radio_button.

# File lib/hexapdf/type/acro_form/button_field.rb, line 172
def concrete_field_type
  if push_button?
    :push_button
  elsif radio_button?
    :radio_button
  else
    :check_box
  end
end
create_appearances(force: false) click to toggle source

Creates appropriate appearances for all widgets if they don't already exist.

The created appearance streams depend on the actual type of the button field. See AppearanceGenerator for the details.

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

# File lib/hexapdf/type/acro_form/button_field.rb, line 232
def create_appearances(force: false)
  appearance_generator_class = document.config.constantize('acro_form.appearance_generator')
  each_widget do |widget|
    normal_appearance = widget.appearance_dict&.normal_appearance
    next if !force && normal_appearance &&
      ((!push_button? && normal_appearance.value.length == 2 &&
        normal_appearance.value.each_value.all?(HexaPDF::Stream)) ||
       (push_button? && normal_appearance.kind_of?(HexaPDF::Stream)))
    if check_box?
      appearance_generator_class.new(widget).create_check_box_appearances
    elsif radio_button?
      appearance_generator_class.new(widget).create_radio_button_appearances
    else
      raise HexaPDF::Error, "Push buttons not yet supported"
    end
  end
end
create_widget(page, defaults: true, value: nil, **values) click to toggle source

Creates a widget for the button field.

If defaults is true, then default values will be set on the widget so that it uses a default appearance.

If the widget is created for a radio button field, the value argument needs to set to the value (a Symbol or an object responding to #to_sym) this widget represents. It can be used with field_value= to set this specific widget of the radio button set to on.

See: Field#create_widget, AppearanceGenerator button field methods

Calls superclass method
# File lib/hexapdf/type/acro_form/button_field.rb, line 208
def create_widget(page, defaults: true, value: nil, **values)
  super(page, allow_embedded: !radio_button?, **values).tap do |widget|
    if check_box?
      widget[:AP] = {N: {Yes: nil, Off: nil}}
    elsif radio_button?
      unless value.respond_to?(:to_sym)
        raise ArgumentError, "Argument 'value' has to be provided for radio buttons " \
          "and needs to respond to #to_sym"
      end
      widget[:AP] = {N: {value.to_sym => nil, Off: nil}}
    end
    next unless defaults
    widget.border_style(color: 0, width: 1, style: (push_button? ? :beveled : :solid))
    widget.background_color(push_button? ? 0.5 : 255)
    widget.marker_style(style: check_box? ? :check : :circle) unless push_button?
  end
end
default_field_value() click to toggle source

Returns the default field value.

See: field_value

# File lib/hexapdf/type/acro_form/button_field.rb, line 160
def default_field_value
  normalized_field_value(:DV)
end
default_field_value=(value) click to toggle source

Sets the default field value.

See: field_value=

# File lib/hexapdf/type/acro_form/button_field.rb, line 167
def default_field_value=(value)
  normalized_field_value_set(:DV, value)
end
field_value() click to toggle source

Returns the field value which depends on the concrete type.

Push buttons

They don't have a value, so nil is always returned.

Check boxes

For check boxes that are in the on state the value true is returned. Otherwise false is returned.

Radio buttons

If no radio button is selected, nil is returned. Otherwise the value (a Symbol) of the specific radio button that is selected is returned.

# File lib/hexapdf/type/acro_form/button_field.rb, line 138
def field_value
  normalized_field_value(:V)
end
field_value=(value) click to toggle source

Sets the field value which depends on the concrete type.

Push buttons

Since push buttons don't store any value, the given value is ignored and nothing is stored for them (e.g a no-op).

Check boxes

Use true for checking the box, i.e. toggling it to the on state, and false for unchecking it.

Radio buttons

To turn all radio buttons off, provide nil as value. Otherwise provide the value (a Symbol or an object responding to #to_sym) of a radio button that should be turned on.

# File lib/hexapdf/type/acro_form/button_field.rb, line 153
def field_value=(value)
  normalized_field_value_set(:V, value)
end
initialize_as_check_box() click to toggle source

Initializes the button field to be a check box.

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

# File lib/hexapdf/type/acro_form/button_field.rb, line 98
def initialize_as_check_box
  self[:V] = :Off
  unflag(:push_button)
  unflag(:radio)
end
initialize_as_push_button() click to toggle source

Initializes the button field to be a push button.

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

# File lib/hexapdf/type/acro_form/button_field.rb, line 88
def initialize_as_push_button
  self[:V] = nil
  flag(:push_button)
  unflag(:radio)
end
initialize_as_radio_button() click to toggle source

Initializes the button field to be a radio button.

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

# File lib/hexapdf/type/acro_form/button_field.rb, line 108
def initialize_as_radio_button
  self[:V] = :Off
  unflag(:push_button)
  flag(:radio)
end
push_button?() click to toggle source

Returns true if this button field represents a push button.

# File lib/hexapdf/type/acro_form/button_field.rb, line 115
def push_button?
  flagged?(:push_button)
end
radio_button?() click to toggle source

Returns true if this button field represents a radio button set.

# File lib/hexapdf/type/acro_form/button_field.rb, line 125
def radio_button?
  !push_button? && flagged?(:radio)
end
radio_button_values() click to toggle source

Returns the array of Symbol values that can be used for the field value of the radio button.

# File lib/hexapdf/type/acro_form/button_field.rb, line 192
def radio_button_values
  each_widget.map do |widget|
    widget.appearance_dict&.normal_appearance&.value&.each_key&.find {|key| key != :Off }
  end.compact
end
update_widgets() click to toggle source

Updates the widgets so that they reflect the current field value.

# File lib/hexapdf/type/acro_form/button_field.rb, line 251
def update_widgets
  return if push_button?
  create_appearances
  value = self[:V]
  each_widget do |widget|
    widget[:AS] = (widget.appearance_dict&.normal_appearance&.key?(value) ? value : :Off)
  end
end

Private Instance Methods

normalized_field_value(key) click to toggle source

Returns the normalized field value for the given key which can be :V or :DV.

See field_value for details.

# File lib/hexapdf/type/acro_form/button_field.rb, line 265
def normalized_field_value(key)
  if push_button?
    nil
  elsif check_box?
    self[key] == check_box_on_name
  elsif radio_button?
    self[key] == :Off ? nil : self[key]
  end
end
normalized_field_value_set(key, value) click to toggle source

Sets the key, either :V or :DV, to the value. The given normalized value is first transformed into the expected value depending on the specific field type.

See field_value= for details.

# File lib/hexapdf/type/acro_form/button_field.rb, line 279
def normalized_field_value_set(key, value)
  return if push_button?
  self[key] = if check_box?
                value == true ? check_box_on_name : :Off
              elsif value.nil?
                :Off
              elsif radio_button_values.include?(value.to_sym)
                value.to_sym
              else
                @document.config['acro_form.on_invalid_value'].call(self, value)
              end
  update_widgets
end