Class: Arrolio::Flowables::TableFlowable
- Inherits:
-
Arrolio::Flowable
- Object
- Arrolio::Flowable
- Arrolio::Flowables::TableFlowable
- Defined in:
- lib/arrolio/flowables/table_flowable.rb
Overview
Real table layout driven by Table::Grid: colspan and rowspan aware cell placement, per-flavor row minimum height, vertical alignment inside cells, borders per cell, header row repeat, continuation caption on split, and table footnotes rendered below the last row.
Constant Summary collapse
- CAPTION_DASH =
Regexp.new("[\u00A0\u2009\u0020]\u2014").freeze
- FOOTNOTE_SPACING =
10.0
Instance Attribute Summary collapse
-
#caption_runs ⇒ Object
readonly
Returns the value of attribute caption_runs.
-
#caption_text ⇒ Object
readonly
Returns the value of attribute caption_text.
-
#cell_padding ⇒ Object
readonly
Returns the value of attribute cell_padding.
-
#continued ⇒ Object
readonly
Returns the value of attribute continued.
-
#footnote_font_size ⇒ Object
readonly
Returns the value of attribute footnote_font_size.
-
#grid ⇒ Object
readonly
Returns the value of attribute grid.
-
#min_row_height ⇒ Object
readonly
Returns the value of attribute min_row_height.
-
#table ⇒ Object
readonly
Returns the value of attribute table.
Attributes inherited from Arrolio::Flowable
Instance Method Summary collapse
-
#do_split(width, remaining_height, _context = nil) ⇒ Object
Splits at welded-group boundaries only — a rowspan cell is never cut by a page break.
- #emit(x, y, width, _context = nil) ⇒ Object
- #height(width, _context = nil) ⇒ Object
-
#initialize(table, style: Style::Definition.new, continued: false, caption_text: nil, caption_runs: nil, caption_style: nil, min_row_height: 0.0, cell_padding: 2.0, footnote_font_size: nil) ⇒ TableFlowable
constructor
A new instance of TableFlowable.
-
#min_keep_height(width, _context = nil) ⇒ Object
What must stay on the same page as a preceding keep-with-next flowable: the caption, the (repeated) header rows, and the first welded body group — a caption or header alone at a page bottom is an orphan.
- #splittable? ⇒ Boolean
- #whole_table_copy ⇒ Object
Methods inherited from Arrolio::Flowable
#keep_together?, #keep_with_next?, #page_break_after?, #page_break_before?, #space_after, #space_before, #split
Constructor Details
#initialize(table, style: Style::Definition.new, continued: false, caption_text: nil, caption_runs: nil, caption_style: nil, min_row_height: 0.0, cell_padding: 2.0, footnote_font_size: nil) ⇒ TableFlowable
Returns a new instance of TableFlowable.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 17 def initialize(table, style: Style::Definition.new, continued: false, caption_text: nil, caption_runs: nil, caption_style: nil, min_row_height: 0.0, cell_padding: 2.0, footnote_font_size: nil) super(style: style) @table = table @continued = continued @caption_runs = caption_runs @caption_text = caption_text || caption_runs&.map(&:text)&.join @caption_style = caption_style @min_row_height = min_row_height.to_f @cell_padding = cell_padding.to_f @footnote_font_size = footnote_font_size || (@style.font_size * 0.9).round(1) @grid = Table::Grid.build(table) end |
Instance Attribute Details
#caption_runs ⇒ Object (readonly)
Returns the value of attribute caption_runs.
11 12 13 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 11 def caption_runs @caption_runs end |
#caption_text ⇒ Object (readonly)
Returns the value of attribute caption_text.
11 12 13 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 11 def caption_text @caption_text end |
#cell_padding ⇒ Object (readonly)
Returns the value of attribute cell_padding.
11 12 13 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 11 def cell_padding @cell_padding end |
#continued ⇒ Object (readonly)
Returns the value of attribute continued.
11 12 13 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 11 def continued @continued end |
#footnote_font_size ⇒ Object (readonly)
Returns the value of attribute footnote_font_size.
11 12 13 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 11 def footnote_font_size @footnote_font_size end |
#grid ⇒ Object (readonly)
Returns the value of attribute grid.
11 12 13 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 11 def grid @grid end |
#min_row_height ⇒ Object (readonly)
Returns the value of attribute min_row_height.
11 12 13 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 11 def min_row_height @min_row_height end |
#table ⇒ Object (readonly)
Returns the value of attribute table.
11 12 13 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 11 def table @table end |
Instance Method Details
#do_split(width, remaining_height, _context = nil) ⇒ Object
Splits at welded-group boundaries only — a rowspan cell is never cut by a page break. When the first group already exceeds the remaining space, no head is returned and the engine moves the whole table to the next page. Footnotes travel with the part carrying the last body row.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 96 def do_split(width, remaining_height, _context = nil) cols = column_widths_for(width) heights = row_heights(cols) header, body = partition_rows header_count = header.length head_groups = [] tail_groups = [] # The head part also carries the caption and the repeated # header rows — they consume the same budget as body rows. used = caption_height(width) + heights[0, header_count].sum body_row_groups.each do |group| group_h = heights[group.first, group.length].sum if used + group_h <= remaining_height head_groups << group used += group_h else tail_groups << group end end head_rows = head_groups.flat_map { |g| body[g.first - header_count, g.length] } tail_rows = tail_groups.flat_map { |g| body[g.first - header_count, g.length] } return [nil, whole_table_copy] if head_rows.empty? if tail_rows.empty? return [build_split(header, head_rows, @continued, footnotes: @table.footnotes), nil] end [build_split(header, head_rows, @continued, footnotes: []), build_split(header, tail_rows, true, footnotes: @table.footnotes)] end |
#emit(x, y, width, _context = nil) ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 53 def emit(x, y, width, _context = nil) cols = column_widths_for(width) heights = row_heights(cols) boxes = [] consumed = 0.0 cursor = y # The caption travels with the table: the head part draws the # full caption, continuations draw the short form. This keeps # the caption from being orphaned at the bottom of a page. if @caption_text caption_h = emit_caption(x, cursor, width, boxes) cursor -= caption_h consumed += caption_h end row_bottoms = row_bottom_positions(cursor, heights) grid.placements.each do |placement| cell_y = row_bottoms[placement.row_index + placement.rowspan - 1] cell_h = heights[placement.row_index, placement.rowspan].sum cell_w = column_span_width(cols, placement) cell_x = x + cols[0, placement.column_index].sum render_cell(placement.cell, cell_x, cell_y, cell_w, cell_h, boxes, header: header_row?(placement.row_index)) end consumed += heights.sum cursor = row_bottoms[-1] || cursor fn_h = emit_footnotes(x, cursor, width, cols, boxes) consumed += fn_h [boxes, consumed] end |
#height(width, _context = nil) ⇒ Object
34 35 36 37 38 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 34 def height(width, _context = nil) cols = column_widths_for(width) caption_height(width) + row_heights(cols).sum + footnote_block_height(width, cols) end |
#min_keep_height(width, _context = nil) ⇒ Object
What must stay on the same page as a preceding keep-with-next flowable: the caption, the (repeated) header rows, and the first welded body group — a caption or header alone at a page bottom is an orphan.
44 45 46 47 48 49 50 51 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 44 def min_keep_height(width, _context = nil) cols = column_widths_for(width) heights = row_heights(cols) header_rows = @table.header.length first_body_group = grid.atomic_row_groups.find { |g| g.first >= header_rows } keep_rows = first_body_group ? first_body_group.last + 1 : header_rows caption_height(width) + heights[0...[keep_rows, heights.length].min].sum end |
#splittable? ⇒ Boolean
87 88 89 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 87 def splittable? true end |
#whole_table_copy ⇒ Object
130 131 132 133 |
# File 'lib/arrolio/flowables/table_flowable.rb', line 130 def whole_table_copy build_split(@table.header, @table.body, @continued, footnotes: @table.footnotes) end |