Class: HexaPDF::Type::Annotations::Widget

Inherits:
HexaPDF::Type::Annotation show all
Defined in:
lib/hexapdf/type/annotations/widget.rb

Overview

Widget annotations are used by interactive forms to represent the appearance of fields and to manage user interactions.

See: PDF2.0 s12.5.6.19, HexaPDF::Type::Annotation

Defined Under Namespace

Classes: AppearanceCharacteristics, BorderStyle, MarkerStyle

Constant Summary

Constants included from DictionaryFields

DictionaryFields::Boolean, DictionaryFields::PDFByteString, DictionaryFields::PDFDate

Instance Attribute Summary

Attributes inherited from Object

#data, #document, #must_be_indirect

Instance Method Summary collapse

Methods inherited from HexaPDF::Type::Annotation

#appearance, #appearance_dict, #create_appearance, #flags, #must_be_indirect?

Methods included from Utils::BitField

#bit_field

Methods inherited from Dictionary

#[], #[]=, define_field, define_type, #delete, #each, each_field, #empty?, field, #key?, #to_hash, type, #type

Methods inherited from Object

#<=>, #==, #cache, #cached?, #clear_cache, deep_copy, #deep_copy, #document?, #eql?, field, #gen, #gen=, #hash, #indirect?, #initialize, #inspect, make_direct, #must_be_indirect?, #null?, #oid, #oid=, #type, #validate, #value, #value=

Constructor Details

This class inherits a constructor from HexaPDF::Object

Instance Method Details

#background_color(*color) ⇒ Object

:call-seq:

widget.background_color                => background_color or nil
widget.background_color(*color)        => widget

Returns the current background color as device color object, or nil if no background color is set, when no argument is given. Otherwise sets the background color using the color argument and returns self.

See HexaPDF::Content::ColorSpace.device_color_from_specification for information on the allowed arguments.



112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/hexapdf/type/annotations/widget.rb', line 112

def background_color(*color)
  if color.empty?
    components = self[:MK]&.[](:BG)
    if components && !components.empty?
      Content::ColorSpace.prenormalized_device_color(components)
    end
  else
    color = Content::ColorSpace.device_color_from_specification(color)
    (self[:MK] ||= {})[:BG] = color.components
    self
  end
end

#border_style(color: nil, width: nil, style: nil) ⇒ Object

:call-seq:

widget.border_style                                      => border_style
widget.border_style(color: 0, width: 1, style: :solid)   => widget

Returns a BorderStyle instance representing the border style of the widget when no argument is given. Otherwise sets the border style of the widget and returns self.

When setting a border style, arguments that are not provided will use the default: a border with a solid, black, 1pt wide line. This also means that multiple invocations will reset all prior values.

color

The color of the border. See HexaPDF::Content::ColorSpace.device_color_from_specification for information on the allowed arguments.

If the special value :transparent is used when setting the color, a transparent is used. A transparent border will return a nil value when getting the border color.

width

The width of the border. If set to 0, no border is shown.

style

Defines how the border is drawn. can be one of the following:

:solid

Draws a solid border.

:beveled

Draws a beveled border.

:inset

Draws an inset border.

:underlined

Draws only the bottom border.

Array

An array specifying a line dash pattern (see HexaPDF::Content::LineDashPattern)



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/hexapdf/type/annotations/widget.rb', line 169

def border_style(color: nil, width: nil, style: nil)
  if color || width || style
    color = if color == :transparent
              []
            else
              Content::ColorSpace.device_color_from_specification(color || 0).components
            end
    width ||= 1
    style ||= :solid

    (self[:MK] ||= {})[:BC] = color
    bs = self[:BS] = {W: width}
    case style
    when :solid then bs[:S] = :S
    when :beveled then bs[:S] = :B
    when :inset then bs[:S] = :I
    when :underlined then bs[:S] = :U
    when Array
      bs[:S] = :D
      bs[:D] = style
    else
      raise ArgumentError, "Unknown value #{style} for style argument"
    end
    self
  else
    result = BorderStyle.new(1, nil, :solid, 0, 0)
    if (ac = self[:MK]) && (bc = ac[:BC]) && !bc.empty?
      result.color = Content::ColorSpace.prenormalized_device_color(bc.value)
    end

    if (bs = self[:BS])
      result.width = bs[:W] if bs.key?(:W)
      result.style = case bs[:S]
                     when :S then :solid
                     when :B then :beveled
                     when :I then :inset
                     when :U then :underlined
                     when :D then bs[:D].value
                     else :solid
                     end
    elsif key?(:Border)
      border = self[:Border]
      result.horizontal_corner_radius = border[0]
      result.vertical_corner_radius = border[1]
      result.width = border[2]
      result.style = border[3] if border[3]
    end

    result
  end
end

#form_fieldObject

Returns the AcroForm field object to which this widget annotation belongs.

Since a widget and a field can share the same dictionary object, the returned object is often just the widget re-wrapped in the correct field class.



92
93
94
95
96
97
98
99
100
# File 'lib/hexapdf/type/annotations/widget.rb', line 92

def form_field
  field = if key?(:Parent) &&
              (tmp = document.wrap(self[:Parent], type: :XXAcroFormField)).terminal_field?
            tmp
          else
            document.wrap(self, type: :XXAcroFormField)
          end
  document.wrap(field, type: :XXAcroFormField, subtype: field[:FT])
end

#marker_style(style: nil, size: nil, color: nil) ⇒ Object

:call-seq:

widget.marker_style                                     => marker_style
widget.marker_style(style: nil, size: nil, color: nil)   => widget

Returns a MarkerStyle instance representing the marker style of the widget when no argument is given. Otherwise sets the button marker style of the widget and returns self.

This method returns valid information only for check boxes and radio buttons!

When setting a marker style, arguments that are not provided will use the default: a black auto-sized checkmark (i.e. :check for for check boxes) or circle (:circle for radio buttons). This also means that multiple invocations will reset all prior values.

Note: The marker is called “normal caption” in the PDF 2.0 spec and the /CA entry of the associated appearance characteristics dictionary. The marker size and color are set using the /DA key on the widget (although /DA is not defined for widget, this is how Acrobat does it).

See: PDF2.0 s12.5.6.19 and s12.7.4.3



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/hexapdf/type/annotations/widget.rb', line 268

def marker_style(style: nil, size: nil, color: nil)
  field = form_field
  if style || size || color
    style ||= (field.check_box? ? :check : :cicrle)
    size ||= 0
    color = Content::ColorSpace.device_color_from_specification(color || 0)
    serialized_color = Content::ColorSpace.serialize_device_color(color)

    self[:MK] ||= {}
    self[:MK][:CA] = case style
                     when :check   then '4'
                     when :circle  then 'l'
                     when :cross   then '8'
                     when :diamond then 'u'
                     when :square  then 'n'
                     when :star    then 'H'
                     when String   then style
                     else
                       raise ArgumentError, "Unknown value #{style} for argument 'style'"
                     end
    self[:DA] = "/ZaDb #{size} Tf #{serialized_color}".strip
  else
    style = case self[:MK]&.[](:CA)
            when '4' then :check
            when 'l' then :circle
            when '8' then :cross
            when 'u' then :diamond
            when 'n' then :square
            when 'H' then :star
            when String then self[:MK][:CA]
            else
              if field.check_box?
                :check
              else
                :circle
              end
            end
    size = 0
    color = HexaPDF::Content::ColorSpace.prenormalized_device_color([0])
    if (da = self[:DA] || field[:DA])
      _, da_size, da_color = AcroForm::VariableTextField.parse_appearance_string(da)
      size = da_size || size
      color = da_color || color
    end

    MarkerStyle.new(style, size, color)
  end
end