Class: HexaPDF::Layout::Box

Inherits:
Object
  • Object
show all
Defined in:
lib/hexapdf/layout/box.rb

Overview

The base class for all layout boxes.

HexaPDF uses the following box model:

  • Each box can specify a width and height. Padding and border are inside, the margin outside of this rectangle.

  • The #content_width and #content_height accessors can be used to get the width and height of the content box without padding and the border.

  • If width or height is set to zero, they are determined automatically during layouting.

Direct Known Subclasses

TextBox

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(width: 0, height: 0, style: Style.new, &block) ⇒ Box

:call-seq:

Box.new(width: 0, height: 0, style: Style.new) {|canv, box| block} -> box

Creates a new Box object with the given width and height that uses the provided block when it is asked to draw itself on a canvas (see #draw).

Since the final location of the box is not known beforehand, the drawing operations inside the block should draw inside the rectangle (0, 0, content_width, content_height) - note that the width and height of the box may not be known beforehand.



93
94
95
96
97
98
99
# File 'lib/hexapdf/layout/box.rb', line 93

def initialize(width: 0, height: 0, style: Style.new, &block)
  @width = @initial_width = width
  @height = @initial_height = height
  @style = (style.kind_of?(Style) ? style : Style.new(style))
  @draw_block = block
  @outline = nil
end

Instance Attribute Details

#heightObject (readonly)

The height of the box, including padding and/or borders.



71
72
73
# File 'lib/hexapdf/layout/box.rb', line 71

def height
  @height
end

#styleObject (readonly)

The style to be applied.

Only the following properties are used:

  • Style#background_color

  • Style#padding

  • Style#border

  • Style#overlay_callback

  • Style#underlay_callback



82
83
84
# File 'lib/hexapdf/layout/box.rb', line 82

def style
  @style
end

#widthObject (readonly)

The width of the box, including padding and/or borders.



68
69
70
# File 'lib/hexapdf/layout/box.rb', line 68

def width
  @width
end

Class Method Details

.create(width: 0, height: 0, content_box: false, **style, &block) ⇒ Object

Creates a new Box object, using the provided block as drawing block (see ::new). Any additional keyword arguments are used for creating the box’s Style object.

If content_box is true, the width and height are taken to mean the content width and height and the style’s padding and border are removed from them appropriately.



56
57
58
59
60
61
62
63
64
65
# File 'lib/hexapdf/layout/box.rb', line 56

def self.create(width: 0, height: 0, content_box: false, **style, &block)
  style = Style.new(style)
  if content_box
    width += style.padding.left + style.padding.right +
      style.border.width.left + style.border.width.right
    height += style.padding.top + style.padding.bottom +
      style.border.width.top + style.border.width.bottom
  end
  new(width: width, height: height, style: style, &block)
end

Instance Method Details

#content_heightObject

The height of the content box, i.e. without padding and/or borders.



108
109
110
111
# File 'lib/hexapdf/layout/box.rb', line 108

def content_height
  [0, height - (@style.padding.top + @style.padding.bottom +
                @style.border.width.top + @style.border.width.bottom)].max
end

#content_widthObject

The width of the content box, i.e. without padding and/or borders.



102
103
104
105
# File 'lib/hexapdf/layout/box.rb', line 102

def content_width
  [0, width - (@style.padding.left + @style.padding.right +
               @style.border.width.left + @style.border.width.right)].max
end

#draw(canvas, x, y) ⇒ Object

Draws the content of the box onto the canvas at the position (x, y).

The coordinate system is translated so that the origin is at the bottom left corner of the **content box** during the drawing operations.

The block specified when creating the box is invoked with the canvas and the box as arguments. Subclasses can specify an on-demand drawing method by setting the @draw_block instance variable to nil or a valid block. This is useful to avoid unnecessary set-up operations when the block does nothing.



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/hexapdf/layout/box.rb', line 132

def draw(canvas, x, y)
  if style.background_color? && style.background_color
    canvas.save_graphics_state do
      canvas.fill_color(style.background_color).rectangle(x, y, width, height).fill
    end
  end

  style.underlays.draw(canvas, x, y, self) if style.underlays?
  style.border.draw(canvas, x, y, width, height) if style.border?

  if @draw_block
    canvas.translate(x + style.padding.left + style.border.width.left,
                     y + style.padding.bottom + style.border.width.bottom) do
      @draw_block.call(canvas, self)
    end
  end

  style.overlays.draw(canvas, x, y, self) if style.overlays?
end

#empty?Boolean

Returns true if no drawing operations are performed.

Returns:

  • (Boolean)


153
154
155
156
157
158
159
# File 'lib/hexapdf/layout/box.rb', line 153

def empty?
  !(@draw_block ||
    (style.background_color? && style.background_color) ||
    (style.underlays? && !style.underlays.none?) ||
    (style.border? && !style.border.none?) ||
    (style.overlays? && !style.overlays.none?))
end

#fit(available_width, available_height, frame) ⇒ Object

Fits the box into the Frame and returns true if fitting was successful.

The default implementation uses the whole available space for width and height if they were initially set to 0. Otherwise the specified dimensions are used.



117
118
119
120
121
# File 'lib/hexapdf/layout/box.rb', line 117

def fit(available_width, available_height, frame)
  @width = (@initial_width > 0 ? @initial_width : available_width)
  @height = (@initial_height > 0 ? @initial_height : available_height)
  @width <= available_width && @height <= available_height
end