Class: Pdfrb::Layout::MultiPageTableBox
- Defined in:
- lib/pdfrb/layout/multi_page_table_box.rb
Overview
Multi-page table: wraps a single TableBox's worth of rows and splits it into per-page fragments when it doesn't fit a single frame. Each fragment is a TableBox whose fit? returns true for the available height; the splitter yields them in document order, optionally repeating a header row on each fragment.
This is intentionally a thin coordinator: it doesn't re-layout cells; it just partitions rows. The actual row drawing is delegated to TableBox, so col/row spans continue to work — but spans that cross a split boundary are clamped at the split (their rowspan is truncated to the rows that fit).
Constant Summary collapse
- DEFAULT_MIN_ROWS_PER_PAGE =
3- DEFAULT_REPEAT_HEADER =
true
Instance Attribute Summary collapse
-
#column_widths ⇒ Object
readonly
Returns the value of attribute column_widths.
-
#header_row_count ⇒ Object
readonly
Returns the value of attribute header_row_count.
-
#min_rows_per_page ⇒ Object
readonly
Returns the value of attribute min_rows_per_page.
-
#rows ⇒ Object
readonly
Returns the value of attribute rows.
Attributes inherited from Box
Instance Method Summary collapse
- #draw_content(canvas, x, y) ⇒ Object
-
#each_fragment(&block) ⇒ Object
Iterate fragments.
- #fit?(available_width, available_height) ⇒ Boolean
-
#fragments(available_width:, first_page_height:, later_page_height:) ⇒ Object
Returns the per-page fragments as an Array of TableBox.
-
#initialize(rows:, column_widths: nil, header_row_count: 0, min_rows_per_page: DEFAULT_MIN_ROWS_PER_PAGE) ⇒ MultiPageTableBox
constructor
A new instance of MultiPageTableBox.
Methods inherited from Box
#draw, #empty?, #supports_position_flow?
Constructor Details
#initialize(rows:, column_widths: nil, header_row_count: 0, min_rows_per_page: DEFAULT_MIN_ROWS_PER_PAGE) ⇒ MultiPageTableBox
Returns a new instance of MultiPageTableBox.
30 31 32 33 34 35 36 37 38 |
# File 'lib/pdfrb/layout/multi_page_table_box.rb', line 30 def initialize(rows:, column_widths: nil, header_row_count: 0, min_rows_per_page: DEFAULT_MIN_ROWS_PER_PAGE, **) super(**) @rows = rows @column_widths = column_widths @header_row_count = header_row_count @min_rows_per_page = min_rows_per_page @fragments = nil end |
Instance Attribute Details
#column_widths ⇒ Object (readonly)
Returns the value of attribute column_widths.
20 21 22 |
# File 'lib/pdfrb/layout/multi_page_table_box.rb', line 20 def column_widths @column_widths end |
#header_row_count ⇒ Object (readonly)
Returns the value of attribute header_row_count.
20 21 22 |
# File 'lib/pdfrb/layout/multi_page_table_box.rb', line 20 def header_row_count @header_row_count end |
#min_rows_per_page ⇒ Object (readonly)
Returns the value of attribute min_rows_per_page.
20 21 22 |
# File 'lib/pdfrb/layout/multi_page_table_box.rb', line 20 def min_rows_per_page @min_rows_per_page end |
#rows ⇒ Object (readonly)
Returns the value of attribute rows.
20 21 22 |
# File 'lib/pdfrb/layout/multi_page_table_box.rb', line 20 def rows @rows end |
Instance Method Details
#draw_content(canvas, x, y) ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/pdfrb/layout/multi_page_table_box.rb', line 87 def draw_content(canvas, x, y) return if @fragments.nil? || @fragments.empty? # Draw the first fragment in place; the Composer is # responsible for placing subsequent fragments on later # pages by calling draw on each fragment directly. offset_y = y @fragments.each do |frag| frag.draw(canvas, x, offset_y) offset_y -= frag.height end end |
#each_fragment(&block) ⇒ Object
Iterate fragments. Yields each TableBox fragment; if a block is absent, returns an Enumerator. Useful for the Composer flow: the first fragment is drawn at the current cursor, subsequent fragments trigger a page break.
104 105 106 107 108 |
# File 'lib/pdfrb/layout/multi_page_table_box.rb', line 104 def each_fragment(&block) return enum_for(:each_fragment) unless block @fragments.each(&block) end |
#fit?(available_width, available_height) ⇒ Boolean
80 81 82 83 84 85 |
# File 'lib/pdfrb/layout/multi_page_table_box.rb', line 80 def fit?(available_width, available_height) @fragments = fragments(available_width: available_width, first_page_height: available_height, later_page_height: available_height) @fragments.any? end |
#fragments(available_width:, first_page_height:, later_page_height:) ⇒ Object
Returns the per-page fragments as an Array of TableBox. The
first fragment fits within available_height; each
subsequent fragment fits within page_height (the next page
may have more room because there's no preceding content).
Mutates internal state (the @fragments cache). Idempotent for the same dimensions.
47 48 49 50 51 52 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 |
# File 'lib/pdfrb/layout/multi_page_table_box.rb', line 47 def fragments(available_width:, first_page_height:, later_page_height:) compute_column_widths(available_width) header = @header_row_count.positive? ? @rows.first(@header_row_count) : [] body = @rows[@header_row_count..] || [] fragments = [] cursor = 0 first_pass = true while cursor < body.length available = first_pass ? first_page_height : later_page_height max_count = rows_that_fit(body, cursor, available) count = if max_count.zero? && cursor.zero? # First fragment must contain at least one row # even if it overflows; otherwise the table is # undrawable. [@min_rows_per_page, body.length].min elsif max_count < @min_rows_per_page # Force at least min_rows_per_page (may overflow). [@min_rows_per_page, body.length - cursor].min else max_count end break if count.zero? chunk = body[cursor, count] rows_for_fragment = header + chunk fragments << build_fragment(rows_for_fragment) cursor += count first_pass = false end fragments end |