Class: HexaPDF::Layout::Box
- Inherits:
-
Object
- Object
- HexaPDF::Layout::Box
- 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.
Instance Attribute Summary collapse
-
#height ⇒ Object
readonly
The height of the box, including padding and/or borders.
-
#style ⇒ Object
readonly
The style to be applied.
-
#width ⇒ Object
readonly
The width of the box, including padding and/or borders.
Class Method Summary collapse
-
.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).
Instance Method Summary collapse
-
#content_height ⇒ Object
The height of the content box, i.e.
-
#content_width ⇒ Object
The width of the content box, i.e.
-
#draw(canvas, x, y) ⇒ Object
Draws the content of the box onto the canvas at the position (x, y).
-
#empty? ⇒ Boolean
Returns
true
if no drawing operations are performed. -
#fit(available_width, available_height, _frame) ⇒ Object
Fits the box into the Frame and returns
true
if fitting was successful. -
#initialize(width: 0, height: 0, style: Style.new, &block) ⇒ Box
constructor
:call-seq: Box.new(width: 0, height: 0, style: Style.new) {|canv, box| block} -> box.
-
#split(_available_width, _available_height, _frame) ⇒ Object
Tries to split the box into two, the first of which needs to fit into the available space, and returns the parts as array.
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.
96 97 98 99 100 101 |
# File 'lib/hexapdf/layout/box.rb', line 96 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 end |
Instance Attribute Details
#height ⇒ Object (readonly)
The height of the box, including padding and/or borders.
74 75 76 |
# File 'lib/hexapdf/layout/box.rb', line 74 def height @height end |
#style ⇒ Object (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
85 86 87 |
# File 'lib/hexapdf/layout/box.rb', line 85 def style @style end |
#width ⇒ Object (readonly)
The width of the box, including padding and/or borders.
71 72 73 |
# File 'lib/hexapdf/layout/box.rb', line 71 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.
59 60 61 62 63 64 65 66 67 68 |
# File 'lib/hexapdf/layout/box.rb', line 59 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_height ⇒ Object
The height of the content box, i.e. without padding and/or borders.
110 111 112 113 |
# File 'lib/hexapdf/layout/box.rb', line 110 def content_height height = @height - reserved_height height < 0 ? 0 : height end |
#content_width ⇒ Object
The width of the content box, i.e. without padding and/or borders.
104 105 106 107 |
# File 'lib/hexapdf/layout/box.rb', line 104 def content_width width = @width - reserved_width width < 0 ? 0 : width 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.
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/hexapdf/layout/box.rb', line 153 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? cx = x cy = y (cx += style.padding.left; cy += style.padding.bottom) if style.padding? (cx += style.border.width.left; cy += style.border.width.bottom) if style.border? draw_content(canvas, cx, cy) style..draw(canvas, x, y, self) if style. end |
#empty? ⇒ Boolean
Returns true
if no drawing operations are performed.
173 174 175 176 177 178 179 |
# File 'lib/hexapdf/layout/box.rb', line 173 def empty? !(@draw_block || (style.background_color? && style.background_color) || (style.underlays? && !style.underlays.none?) || (style.border? && !style.border.none?) || (style. && !style..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.
119 120 121 122 123 |
# File 'lib/hexapdf/layout/box.rb', line 119 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 |
#split(_available_width, _available_height, _frame) ⇒ Object
Tries to split the box into two, the first of which needs to fit into the available space, and returns the parts as array.
In many cases the first box in the list will be this box, meaning that even when #fit fails, a part of the box may still fit. Note that #fit may not be called if the first box is this box since it is assumed that it is already fitted. If not even a part of this box fits into the available space, nil
should be returned as the first array element.
Possible return values:
- [self]
-
The box fully fits into the available space.
- [nil, self]
-
The box can’t be split or no part of the box fits into the available space.
- [self, new_box]
-
A part of the box fits and a new box is returned for the rest.
This default implementation provides no splitting functionality.
140 141 142 |
# File 'lib/hexapdf/layout/box.rb', line 140 def split(_available_width, _available_height, _frame) [nil, self] end |