Class: Arrolio::Table::Grid

Inherits:
Object
  • Object
show all
Defined in:
lib/arrolio/table/grid.rb

Overview

Occupancy grid over a Content::Table, honoring colspan and rowspan. Answers the two questions every table consumer asks: which column does each cell actually occupy, and which rows are welded together by a vertical span (and therefore cannot be split apart across pages).

Built once per layout pass and shared by AutoLayout (natural widths), TableFlowable (row heights, cell placement), and splitting (atomic row groups).

Defined Under Namespace

Classes: Placement

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(placements:, row_count:, column_count:) ⇒ Grid

Returns a new instance of Grid.



57
58
59
60
61
62
63
64
65
# File 'lib/arrolio/table/grid.rb', line 57

def initialize(placements:, row_count:, column_count:)
  @placements = placements.freeze
  @row_count = row_count
  @column_count = column_count
  @by_row = Array.new(row_count) { [] }
  @placements.each { |p| @by_row[p.row_index] << p }
  @by_row.each(&:freeze)
  freeze
end

Instance Attribute Details

#column_countObject (readonly)

Returns the value of attribute column_count.



29
30
31
# File 'lib/arrolio/table/grid.rb', line 29

def column_count
  @column_count
end

#placementsObject (readonly)

Returns the value of attribute placements.



29
30
31
# File 'lib/arrolio/table/grid.rb', line 29

def placements
  @placements
end

#row_countObject (readonly)

Returns the value of attribute row_count.



29
30
31
# File 'lib/arrolio/table/grid.rb', line 29

def row_count
  @row_count
end

Class Method Details

.build(table) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/arrolio/table/grid.rb', line 31

def self.build(table)
  rows = table.rows
  occupied = {}
  placements = []
  rows.each_with_index do |row, row_index|
    column_index = 0
    row.cells.each do |cell|
      column_index += 1 while occupied[[row_index, column_index]]
      colspan = cell.colspan.to_i
      rowspan = cell.rowspan.to_i
      placements << Placement.new(
        cell: cell, row_index: row_index, column_index: column_index,
        colspan: colspan, rowspan: rowspan
      )
      rowspan.times do |r|
        colspan.times do |c|
          occupied[[row_index + r, column_index + c]] = true
        end
      end
      column_index += colspan
    end
  end
  new(placements: placements, row_count: rows.length,
      column_count: occupied.keys.map(&:last).max.to_i + 1)
end

Instance Method Details

#atomic_row_groupsObject

Rows welded together by rowspan cells, as arrays of row indexes in ascending order. Rows not covered by any span come back as single-element groups. Splitting the table across pages must happen between groups, never inside one.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/arrolio/table/grid.rb', line 75

def atomic_row_groups
  groups = []
  group = []
  welded = welded_rows
  (0...@row_count).each do |row_index|
    group << row_index
    next if welded.include?(row_index + 1)

    groups << group.freeze
    group = []
  end
  groups << group.freeze unless group.empty?
  groups.freeze
end

#placements_starting_in(row_index) ⇒ Object



67
68
69
# File 'lib/arrolio/table/grid.rb', line 67

def placements_starting_in(row_index)
  @by_row[row_index] || []
end