Class: Prawn::Table::Cell

Inherits:
Object
  • Object
show all
Defined in:
lib/prawn/table/cell.rb,
lib/prawn/table/cell/text.rb,
lib/prawn/table/cell/image.rb,
lib/prawn/table/cell/in_table.rb,
lib/prawn/table/cell/subtable.rb,
lib/prawn/table/cell/span_dummy.rb

Overview

A Cell is a rectangular area of the page into which content is drawn. It has a framework for sizing itself and adding padding and simple styling. There are several standard Cell subclasses that handle things like text, Tables, and (in the future) stamps, images, and arbitrary content.

Cells are a basic building block for table support (see Prawn::Table).

Please subclass me if you want new content types! I'm designed to be very extensible. See the different standard Cell subclasses in lib/prawn/table/cell/*.rb for a template.

Direct Known Subclasses

Image, SpanDummy, Subtable, Text

Defined Under Namespace

Modules: InTable Classes: Image, SpanDummy, Subtable, Text

Constant Summary

FPTolerance =

A small amount added to the bounding box width to cover over floating- point errors when round-tripping from content_width to width and back. This does not change cell positioning; it only slightly expands each cell's bounding box width so that rounding error does not prevent a cell from rendering.

1

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Cell) initialize(pdf, point, options = {})

Sets up a cell on the document pdf, at the given x/y location point, with the given options. Cell, like Table, follows the "options set accessors" paradigm (see "Options" under the Table documentation), so any cell accessor cell.foo = :bar can be set by providing the option :foo => :bar here.



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/prawn/table/cell.rb', line 206

def initialize(pdf, point, options={})
  @pdf   = pdf
  @point = point

  # Set defaults; these can be changed by options
  @padding       = [5, 5, 5, 5]
  @borders       = [:top, :bottom, :left, :right]
  @border_widths = [1] * 4
  @border_colors = ['000000'] * 4
  @border_lines  = [:solid] * 4
  @colspan = 1
  @rowspan = 1
  @dummy_cells = []

  options.each { |k, v| send("#{k}=", v) }

  @initializer_run = true
end

Instance Attribute Details

- (Object) background_color

The background color, if any, for this cell. Specified in HTML RGB format, e.g., "ccffff". The background is drawn under the whole cell, including any padding.



140
141
142
# File 'lib/prawn/table/cell.rb', line 140

def background_color
  @background_color
end

- (Object) border_colors (readonly)

HTML RGB-format ("ccffff") border colors: [top, right, bottom, left].



124
125
126
# File 'lib/prawn/table/cell.rb', line 124

def border_colors
  @border_colors
end

- (Object) border_lines (readonly)

Line style



128
129
130
# File 'lib/prawn/table/cell.rb', line 128

def border_lines
  @border_lines
end

- (Object) border_widths (readonly)

Width, in PDF points, of the cell's borders: [top, right, bottom, left].



120
121
122
# File 'lib/prawn/table/cell.rb', line 120

def border_widths
  @border_widths
end

- (Object) borders

Specifies which borders to enable. Must be an array of zero or more of: [:left, :right, :top, :bottom].



116
117
118
# File 'lib/prawn/table/cell.rb', line 116

def borders
  @borders
end

- (Object) colspan

Number of columns this cell spans. Defaults to 1.



144
145
146
# File 'lib/prawn/table/cell.rb', line 144

def colspan
  @colspan
end

- (Object) content

Specifies the content for the cell. Must be a "cellable" object. See the "Data" section of the Prawn::Table documentation for details on cellable objects.



134
135
136
# File 'lib/prawn/table/cell.rb', line 134

def content
  @content
end

- (Object) dummy_cells (readonly)

Array of SpanDummy cells (if any) that represent the other cells in this span group. They know their own width / height, but do not draw anything.



154
155
156
# File 'lib/prawn/table/cell.rb', line 154

def dummy_cells
  @dummy_cells
end

- (Object) height

Returns the cell's height in points, inclusive of padding. If the cell is the master cell of a rowspan, returns the width of the entire span group.



312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/prawn/table/cell.rb', line 312

def height
  return height_ignoring_span if @colspan == 1 && @rowspan == 1

  # We're in a span group; get the maximum height per row (including the
  # master cell) and sum each row.
  row_heights = Hash.new(0)
  dummy_cells.each do |cell|
    row_heights[cell.row] = [row_heights[cell.row], cell.height].max
  end
  row_heights[row] = [row_heights[row], height_ignoring_span].max
  row_heights.values.inject(0, &:+)
end

- (Object) padding

Amount of dead space (in PDF points) inside the borders but outside the content. Padding defaults to 5pt.



55
56
57
# File 'lib/prawn/table/cell.rb', line 55

def padding
  @padding
end

- (Object) rowspan

Number of rows this cell spans. Defaults to 1.



148
149
150
# File 'lib/prawn/table/cell.rb', line 148

def rowspan
  @rowspan
end

Class Method Details

+ (Object) draw_cells(cells)

Given an array of pairs [cell, pt], draws each cell at its corresponding pt, making sure all backgrounds are behind all borders and content.



407
408
409
410
411
412
413
414
415
416
417
# File 'lib/prawn/table/cell.rb', line 407

def self.draw_cells(cells)
  cells.each do |cell, pt|
    cell.set_width_constraints
    cell.draw_background(pt)
  end

  cells.each do |cell, pt|
    cell.draw_borders(pt)
    cell.draw_bounded_content(pt)
  end
end

+ (Object) make(pdf, content, options = {})

Instantiates a Cell based on the given options. The particular class of cell returned depends on the :content argument. See the Prawn::Table documentation under "Data" for allowable content types.



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/prawn/table/cell.rb', line 160

def self.make(pdf, content, options={})
  at = options.delete(:at) || [0, pdf.cursor]
  content = content.to_s if content.nil? || content.kind_of?(Numeric) ||
    content.kind_of?(Date)

  if content.is_a?(Hash)
    if img = content[:image]
      return Cell::Image.new(pdf, at, content)
    end
    options.update(content)
    content = options[:content]
  else
    options[:content] = content
  end

  options[:content] = content = "" if content.nil?

  case content
  when Prawn::Table::Cell
    content
  when String
    Cell::Text.new(pdf, at, options)
  when Prawn::Table
    Cell::Subtable.new(pdf, at, options)
  when Array
    subtable = Prawn::Table.new(options[:content], pdf, {})
    Cell::Subtable.new(pdf, at, options.merge(:content => subtable))
  else
    raise Errors::UnrecognizedTableContent
  end
end

Instance Method Details

- (Object) avg_spanned_min_width

Min-width of the span divided by the number of columns.



81
82
83
# File 'lib/prawn/table/cell.rb', line 81

def avg_spanned_min_width
  min_width.to_f / colspan
end

- (Object) border_bottom_color



562
563
564
# File 'lib/prawn/table/cell.rb', line 562

def border_bottom_color
  @border_colors[2]
end

- (Object) border_bottom_color=(val)



566
567
568
# File 'lib/prawn/table/cell.rb', line 566

def border_bottom_color=(val)
  @border_colors[2] = val
end

- (Object) border_bottom_line



688
689
690
# File 'lib/prawn/table/cell.rb', line 688

def border_bottom_line
  @borders.include?(:bottom) ? @border_lines[2] : 0
end

- (Object) border_bottom_line=(val)



692
693
694
# File 'lib/prawn/table/cell.rb', line 692

def border_bottom_line=(val)
  @border_lines[2] = val
end

- (Object) border_bottom_width



620
621
622
# File 'lib/prawn/table/cell.rb', line 620

def border_bottom_width
  @borders.include?(:bottom) ? @border_widths[2] : 0
end

- (Object) border_bottom_width=(val)



624
625
626
# File 'lib/prawn/table/cell.rb', line 624

def border_bottom_width=(val)
  @border_widths[2] = val
end

- (Object) border_color=(color) Also known as: border_colors=

Sets border colors on this cell. The argument can be one of:

  • an integer (sets all colors)

  • a two-element array [vertical, horizontal]

  • a three-element array [top, horizontal, bottom]

  • a four-element array [top, right, bottom, left]



519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
# File 'lib/prawn/table/cell.rb', line 519

def border_color=(color)
  @border_colors = case
  when color.nil?
    ["000000"] * 4
  when String === color # all colors
    [color, color, color, color]
  when color.length == 2 # vert, horiz
    [color[0], color[1], color[0], color[1]]
  when color.length == 3 # top, horiz, bottom
    [color[0], color[1], color[2], color[1]]
  when color.length == 4 # top, right, bottom, left
    [color[0], color[1], color[2], color[3]]
  else
    raise ArgumentError, ":border_color must be a string " +
      "or an array [v,h] or [t,r,b,l]"
  end
end

- (Object) border_left_color



570
571
572
# File 'lib/prawn/table/cell.rb', line 570

def border_left_color
  @border_colors[3]
end

- (Object) border_left_color=(val)



574
575
576
# File 'lib/prawn/table/cell.rb', line 574

def border_left_color=(val)
  @border_colors[3] = val
end

- (Object) border_left_line



696
697
698
# File 'lib/prawn/table/cell.rb', line 696

def border_left_line
  @borders.include?(:left) ? @border_lines[3] : 0
end

- (Object) border_left_line=(val)



700
701
702
# File 'lib/prawn/table/cell.rb', line 700

def border_left_line=(val)
  @border_lines[3] = val
end

- (Object) border_left_width



628
629
630
# File 'lib/prawn/table/cell.rb', line 628

def border_left_width
  @borders.include?(:left) ? @border_widths[3] : 0
end

- (Object) border_left_width=(val)



632
633
634
# File 'lib/prawn/table/cell.rb', line 632

def border_left_width=(val)
  @border_widths[3] = val
end

- (Object) border_line=(line) Also known as: border_lines=

Sets border line style on this cell. The argument can be one of:

Possible values are: :solid, :dashed, :dotted

  • one value (sets all lines)

  • a two-element array [vertical, horizontal]

  • a three-element array [top, horizontal, bottom]

  • a four-element array [top, right, bottom, left]



653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
# File 'lib/prawn/table/cell.rb', line 653

def border_line=(line)
  @border_lines = case
  when line.nil?
    [:solid] * 4
  when line.length == 1 # all lines
    [line[0]] * 4
  when line.length == 2
    [line[0], line[1], line[0], line[1]]
  when line.length == 3
    [line[0], line[1], line[2], line[1]]
  when line.length == 4
    [line[0], line[1], line[2], line[3]]
  else
    raise ArgumentError, "border_line must be one of :solid, :dashed, "
      ":dotted or an array [v,h] or [t,r,b,l]"
  end
end

- (Object) border_right_color



554
555
556
# File 'lib/prawn/table/cell.rb', line 554

def border_right_color
  @border_colors[1]
end

- (Object) border_right_color=(val)



558
559
560
# File 'lib/prawn/table/cell.rb', line 558

def border_right_color=(val)
  @border_colors[1] = val
end

- (Object) border_right_line



680
681
682
# File 'lib/prawn/table/cell.rb', line 680

def border_right_line
  @borders.include?(:right) ? @border_lines[1] : 0
end

- (Object) border_right_line=(val)



684
685
686
# File 'lib/prawn/table/cell.rb', line 684

def border_right_line=(val)
  @border_lines[1] = val
end

- (Object) border_right_width



612
613
614
# File 'lib/prawn/table/cell.rb', line 612

def border_right_width
  @borders.include?(:right) ? @border_widths[1] : 0
end

- (Object) border_right_width=(val)



616
617
618
# File 'lib/prawn/table/cell.rb', line 616

def border_right_width=(val)
  @border_widths[1] = val
end

- (Object) border_top_color



538
539
540
# File 'lib/prawn/table/cell.rb', line 538

def border_top_color
  @border_colors[0]
end

- (Object) border_top_color=(val)



542
543
544
# File 'lib/prawn/table/cell.rb', line 542

def border_top_color=(val)
  @border_colors[0] = val
end

- (Object) border_top_line



672
673
674
# File 'lib/prawn/table/cell.rb', line 672

def border_top_line
  @borders.include?(:top) ? @border_lines[0] : 0
end

- (Object) border_top_line=(val)



676
677
678
# File 'lib/prawn/table/cell.rb', line 676

def border_top_line=(val)
  @border_lines[0] = val
end

- (Object) border_top_width



604
605
606
# File 'lib/prawn/table/cell.rb', line 604

def border_top_width
  @borders.include?(:top) ? @border_widths[0] : 0
end

- (Object) border_top_width=(val)



608
609
610
# File 'lib/prawn/table/cell.rb', line 608

def border_top_width=(val)
  @border_widths[0] = val
end

- (Object) border_width=(width) Also known as: border_widths=

Sets border widths on this cell. The argument can be one of:

  • an integer (sets all widths)

  • a two-element array [vertical, horizontal]

  • a three-element array [top, horizontal, bottom]

  • a four-element array [top, right, bottom, left]



585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
# File 'lib/prawn/table/cell.rb', line 585

def border_width=(width)
  @border_widths = case
  when width.nil?
    ["000000"] * 4
  when Numeric === width # all widths
    [width, width, width, width]
  when width.length == 2 # vert, horiz
    [width[0], width[1], width[0], width[1]]
  when width.length == 3 # top, horiz, bottom
    [width[0], width[1], width[2], width[1]]
  when width.length == 4 # top, right, bottom, left
    [width[0], width[1], width[2], width[3]]
  else
    raise ArgumentError, ":border_width must be a string " +
      "or an array [v,h] or [t,r,b,l]"
  end
end

- (Object) content_height

Returns the height of the bare content in the cell, excluding padding.



327
328
329
330
331
332
333
# File 'lib/prawn/table/cell.rb', line 327

def content_height
  if @height # manually set
    return @height - padding_top - padding_bottom
  end

  natural_content_height
end

- (Object) content_width

Returns the width of the bare content in the cell, excluding padding.



277
278
279
280
281
282
283
# File 'lib/prawn/table/cell.rb', line 277

def content_width
  if @width # manually set
    return @width - padding_left - padding_right
  end

  natural_content_width
end

- (Object) draw(pt = [x, y])

Draws the cell onto the document. Pass in a point [x,y] to override the location at which the cell is drawn.

If drawing a group of cells at known positions, look into Cell.draw_cells, which ensures that the backgrounds, borders, and content are all drawn in correct order so as not to overlap.



399
400
401
# File 'lib/prawn/table/cell.rb', line 399

def draw(pt=[x, y])
  Prawn::Table::Cell.draw_cells([[self, pt]])
end

- (Object) draw_background(pt)

Draws the cell's background color.



706
707
708
709
710
711
712
713
# File 'lib/prawn/table/cell.rb', line 706

def draw_background(pt)
  if @background_color
    @pdf.mask(:fill_color) do
      @pdf.fill_color @background_color
      @pdf.fill_rectangle pt, width, height
    end
  end
end

- (Object) draw_borders(pt)

Draws borders around the cell. Borders are centered on the bounds of the cell outside of any padding, so the caller is responsible for setting appropriate padding to ensure the border does not overlap with cell content.



720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
# File 'lib/prawn/table/cell.rb', line 720

def draw_borders(pt)
  x, y = pt

  @pdf.mask(:line_width, :stroke_color) do
    @borders.each do |border|
      idx = {:top => 0, :right => 1, :bottom => 2, :left => 3}[border]
      border_color = @border_colors[idx]
      border_width = @border_widths[idx]
      border_line  = @border_lines[idx]

      next if border_width <= 0

      # Left and right borders are drawn one-half border beyond the center
      # of the corner, so that the corners end up square.
      from, to = case border
                 when :top
                   [[x, y], [x+width, y]]
                 when :bottom
                   [[x, y-height], [x+width, y-height]]
                 when :left
                   [[x, y + (border_top_width / 2.0)],
                    [x, y - height - (border_bottom_width / 2.0)]]
                 when :right
                   [[x+width, y + (border_top_width / 2.0)],
                    [x+width, y - height - (border_bottom_width / 2.0)]]
                 end

      case border_line
      when :dashed
        @pdf.dash border_width * 4
      when :dotted
        @pdf.dash border_width, :space => border_width * 2
      when :solid
        # normal line style
      else
        raise ArgumentError, "border_line must be :solid, :dotted or" +
          " :dashed"
      end
      
      @pdf.line_width   = border_width
      @pdf.stroke_color = border_color
      @pdf.stroke_line(from, to)
      @pdf.undash
    end
  end
end

- (Object) draw_bounded_content(pt)

Draws the cell's content at the point provided.



421
422
423
424
425
426
427
428
429
# File 'lib/prawn/table/cell.rb', line 421

def draw_bounded_content(pt)
  @pdf.float do
    @pdf.bounding_box([pt[0] + padding_left, pt[1] - padding_top],
                      :width  => spanned_content_width + FPTolerance,
                      :height => spanned_content_height + FPTolerance) do
      draw_content
    end
  end
end

- (Object) draw_content

Draws cell content within the cell's bounding box. Must be implemented in subclasses.

Raises:

  • (NotImplementedError)


770
771
772
# File 'lib/prawn/table/cell.rb', line 770

def draw_content
  raise NotImplementedError, "subclasses must implement draw_content"
end

- (Object) height_ignoring_span

Returns the cell's height in points, inclusive of padding, in its first row only.



302
303
304
305
306
# File 'lib/prawn/table/cell.rb', line 302

def height_ignoring_span
  # We can't ||= here because the FP error accumulates on the round-trip
  # from #content_height.
  @height || (content_height + padding_top + padding_bottom)
end

- (Object) max_width

Maximum width of the entire span group this cell controls.



95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/prawn/table/cell.rb', line 95

def max_width
  return max_width_ignoring_span if @colspan == 1

  # Sum the smallest max-width from each column in the group, including
  # myself.
  max_widths = Hash.new(0)
  dummy_cells.each do |cell|
    max_widths[cell.column] =
      [max_widths[cell.column], cell.max_width].min
  end
  max_widths[column] = [max_widths[column], max_width_ignoring_span].min
  max_widths.values.inject(0, &:+)
end

- (Object) max_width_ignoring_span

If provided, the maximum width that this cell can be drawn in, within its column.



88
89
90
91
# File 'lib/prawn/table/cell.rb', line 88

def max_width_ignoring_span
  set_width_constraints
  @max_width
end

- (Object) min_width

Minimum width of the entire span group this cell controls.



66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/prawn/table/cell.rb', line 66

def min_width
  return min_width_ignoring_span if @colspan == 1

  # Sum up the largest min-width from each column, including myself.
  min_widths = Hash.new(0)
  dummy_cells.each do |cell|
    min_widths[cell.column] =
      [min_widths[cell.column], cell.min_width].max
  end
  min_widths[column] = [min_widths[column], min_width_ignoring_span].max
  min_widths.values.inject(0, &:+)
end

- (Object) min_width_ignoring_span

If provided, the minimum width that this cell in its column will permit.



59
60
61
62
# File 'lib/prawn/table/cell.rb', line 59

def min_width_ignoring_span
  set_width_constraints
  @min_width
end

- (Object) natural_content_height

Returns the height this cell would naturally take on, absent constraints. Must be implemented in subclasses.

Raises:

  • (NotImplementedError)


344
345
346
347
# File 'lib/prawn/table/cell.rb', line 344

def natural_content_height
  raise NotImplementedError,
    "subclasses must implement natural_content_height"
end

- (Object) natural_content_width

Returns the width this cell would naturally take on, absent other constraints. Must be implemented in subclasses.

Raises:

  • (NotImplementedError)


294
295
296
297
# File 'lib/prawn/table/cell.rb', line 294

def natural_content_width
  raise NotImplementedError,
    "subclasses must implement natural_content_width"
end

- (Object) padding_bottom



496
497
498
# File 'lib/prawn/table/cell.rb', line 496

def padding_bottom
  @padding[2]
end

- (Object) padding_bottom=(val)



500
501
502
# File 'lib/prawn/table/cell.rb', line 500

def padding_bottom=(val)
  @padding[2] = val
end

- (Object) padding_left



504
505
506
# File 'lib/prawn/table/cell.rb', line 504

def padding_left
  @padding[3]
end

- (Object) padding_left=(val)



508
509
510
# File 'lib/prawn/table/cell.rb', line 508

def padding_left=(val)
  @padding[3] = val
end

- (Object) padding_right



488
489
490
# File 'lib/prawn/table/cell.rb', line 488

def padding_right
  @padding[1]
end

- (Object) padding_right=(val)



492
493
494
# File 'lib/prawn/table/cell.rb', line 492

def padding_right=(val)
  @padding[1] = val
end

- (Object) padding_top



480
481
482
# File 'lib/prawn/table/cell.rb', line 480

def padding_top
  @padding[0]
end

- (Object) padding_top=(val)



484
485
486
# File 'lib/prawn/table/cell.rb', line 484

def padding_top=(val)
  @padding[0] = val
end

- (Object) set_width_constraints

Sets the cell's minimum and maximum width. Deferred until requested because padding and size can change.



639
640
641
642
# File 'lib/prawn/table/cell.rb', line 639

def set_width_constraints
  @min_width ||= padding_left + padding_right
  @max_width ||= @pdf.bounds.width
end

- (Object) spanned_content_height

Height of the entire span group.



337
338
339
# File 'lib/prawn/table/cell.rb', line 337

def spanned_content_height
  height - padding_top - padding_bottom
end

- (Object) spanned_content_width

Width of the entire span group.



287
288
289
# File 'lib/prawn/table/cell.rb', line 287

def spanned_content_width
  width - padding_left - padding_right
end

- (Object) style(options = {}, &block)

Supports setting multiple properties at once.

cell.style(:padding => 0, :border_width => 2)

is the same as:

cell.padding = 0
cell.border_width = 2


234
235
236
237
238
239
240
# File 'lib/prawn/table/cell.rb', line 234

def style(options={}, &block)
  options.each { |k, v| send("#{k}=", v) }

  # The block form supports running a single block for multiple cells, as
  # in Cells#style.
  block.call(self) if block
end

- (Object) width

Returns the cell's width in points, inclusive of padding. If the cell is the master cell of a colspan, returns the width of the entire span group.



255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/prawn/table/cell.rb', line 255

def width
  return width_ignoring_span if @colspan == 1 && @rowspan == 1

  # We're in a span group; get the maximum width per column (including
  # the master cell) and sum each column.
  column_widths = Hash.new(0)
  dummy_cells.each do |cell|
    column_widths[cell.column] =
      [column_widths[cell.column], cell.width].max
  end
  column_widths[column] = [column_widths[column], width_ignoring_span].max
  column_widths.values.inject(0, &:+)
end

- (Object) width=(w)

Manually sets the cell's width, inclusive of padding.



271
272
273
# File 'lib/prawn/table/cell.rb', line 271

def width=(w)
  @width = @min_width = @max_width = w
end

- (Object) width_ignoring_span

Returns the width of the cell in its first column alone, ignoring any colspans.



245
246
247
248
249
# File 'lib/prawn/table/cell.rb', line 245

def width_ignoring_span
  # We can't ||= here because the FP error accumulates on the round-trip
  # from #content_width.
  @width || (content_width + padding_left + padding_right)
end

- (Object) x

x-position of the cell within the parent bounds.



433
434
435
# File 'lib/prawn/table/cell.rb', line 433

def x
  @point[0]
end

- (Object) x=(val)

Set the x-position of the cell within the parent bounds.



439
440
441
# File 'lib/prawn/table/cell.rb', line 439

def x=(val)
  @point[0] = val
end

- (Object) y

y-position of the cell within the parent bounds.



445
446
447
# File 'lib/prawn/table/cell.rb', line 445

def y
  @point[1]
end

- (Object) y=(val)

Set the y-position of the cell within the parent bounds.



451
452
453
# File 'lib/prawn/table/cell.rb', line 451

def y=(val)
  @point[1] = val
end