fullcirclegroup-prawn 0.2.99.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. data/COPYING +340 -0
  2. data/LICENSE +56 -0
  3. data/README +47 -0
  4. data/Rakefile +76 -0
  5. data/data/fonts/Activa.ttf +0 -0
  6. data/data/fonts/Chalkboard.ttf +0 -0
  7. data/data/fonts/Courier-Bold.afm +342 -0
  8. data/data/fonts/Courier-BoldOblique.afm +342 -0
  9. data/data/fonts/Courier-Oblique.afm +342 -0
  10. data/data/fonts/Courier.afm +342 -0
  11. data/data/fonts/DejaVuSans.ttf +0 -0
  12. data/data/fonts/Dustismo_Roman.ttf +0 -0
  13. data/data/fonts/Helvetica-Bold.afm +2827 -0
  14. data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  15. data/data/fonts/Helvetica-Oblique.afm +3051 -0
  16. data/data/fonts/Helvetica.afm +3051 -0
  17. data/data/fonts/MustRead.html +19 -0
  18. data/data/fonts/Symbol.afm +213 -0
  19. data/data/fonts/Times-Bold.afm +2588 -0
  20. data/data/fonts/Times-BoldItalic.afm +2384 -0
  21. data/data/fonts/Times-Italic.afm +2667 -0
  22. data/data/fonts/Times-Roman.afm +2419 -0
  23. data/data/fonts/ZapfDingbats.afm +225 -0
  24. data/data/fonts/comicsans.ttf +0 -0
  25. data/data/fonts/gkai00mp.ttf +0 -0
  26. data/data/images/arrow.png +0 -0
  27. data/data/images/arrow2.png +0 -0
  28. data/data/images/barcode_issue.png +0 -0
  29. data/data/images/dice.alpha +0 -0
  30. data/data/images/dice.dat +0 -0
  31. data/data/images/dice.png +0 -0
  32. data/data/images/page_white_text.alpha +0 -0
  33. data/data/images/page_white_text.dat +0 -0
  34. data/data/images/page_white_text.png +0 -0
  35. data/data/images/pigs.jpg +0 -0
  36. data/data/images/rails.dat +0 -0
  37. data/data/images/rails.png +0 -0
  38. data/data/images/ruport.png +0 -0
  39. data/data/images/ruport_data.dat +0 -0
  40. data/data/images/ruport_transparent.png +0 -0
  41. data/data/images/ruport_type0.png +0 -0
  42. data/data/images/stef.jpg +0 -0
  43. data/data/images/web-links.dat +1 -0
  44. data/data/images/web-links.png +0 -0
  45. data/data/shift_jis_text.txt +1 -0
  46. data/examples/addressbook.csv +6 -0
  47. data/examples/alignment.rb +16 -0
  48. data/examples/bounding_boxes.rb +30 -0
  49. data/examples/canvas.rb +12 -0
  50. data/examples/cell.rb +38 -0
  51. data/examples/chinese_text_wrapping.rb +17 -0
  52. data/examples/currency.csv +1834 -0
  53. data/examples/curves.rb +10 -0
  54. data/examples/family_based_styling.rb +21 -0
  55. data/examples/fancy_table.rb +61 -0
  56. data/examples/flowing_text_with_header_and_footer.rb +72 -0
  57. data/examples/font_size.rb +27 -0
  58. data/examples/hexagon.rb +14 -0
  59. data/examples/image.rb +23 -0
  60. data/examples/image2.rb +13 -0
  61. data/examples/image_flow.rb +34 -0
  62. data/examples/kerning.rb +27 -0
  63. data/examples/lazy_bounding_boxes.rb +19 -0
  64. data/examples/line.rb +31 -0
  65. data/examples/multi_page_layout.rb +14 -0
  66. data/examples/page_geometry.rb +28 -0
  67. data/examples/png_types.rb +23 -0
  68. data/examples/polygons.rb +16 -0
  69. data/examples/position_by_baseline.rb +26 -0
  70. data/examples/ruport_formatter.rb +50 -0
  71. data/examples/ruport_helpers.rb +18 -0
  72. data/examples/russian_boxes.rb +34 -0
  73. data/examples/simple_text.rb +15 -0
  74. data/examples/simple_text_ttf.rb +16 -0
  75. data/examples/sjis.rb +21 -0
  76. data/examples/span.rb +27 -0
  77. data/examples/table.rb +47 -0
  78. data/examples/table_header_color.rb +16 -0
  79. data/examples/text_flow.rb +65 -0
  80. data/examples/top_and_bottom_cells.rb +40 -0
  81. data/examples/utf8.rb +12 -0
  82. data/lib/prawn.rb +67 -0
  83. data/lib/prawn/compatibility.rb +46 -0
  84. data/lib/prawn/document.rb +309 -0
  85. data/lib/prawn/document/bounding_box.rb +362 -0
  86. data/lib/prawn/document/internals.rb +113 -0
  87. data/lib/prawn/document/page_geometry.rb +79 -0
  88. data/lib/prawn/document/span.rb +47 -0
  89. data/lib/prawn/document/table.rb +350 -0
  90. data/lib/prawn/document/text.rb +196 -0
  91. data/lib/prawn/errors.rb +48 -0
  92. data/lib/prawn/font.rb +356 -0
  93. data/lib/prawn/font/cmap.rb +59 -0
  94. data/lib/prawn/font/metrics.rb +378 -0
  95. data/lib/prawn/font/wrapping.rb +47 -0
  96. data/lib/prawn/graphics.rb +252 -0
  97. data/lib/prawn/graphics/cell.rb +264 -0
  98. data/lib/prawn/graphics/color.rb +132 -0
  99. data/lib/prawn/images.rb +336 -0
  100. data/lib/prawn/images/jpg.rb +45 -0
  101. data/lib/prawn/images/png.rb +199 -0
  102. data/lib/prawn/pdf_object.rb +73 -0
  103. data/lib/prawn/reference.rb +56 -0
  104. data/spec/bounding_box_spec.rb +141 -0
  105. data/spec/document_spec.rb +181 -0
  106. data/spec/font_spec.rb +141 -0
  107. data/spec/graphics_spec.rb +209 -0
  108. data/spec/images_spec.rb +68 -0
  109. data/spec/jpg_spec.rb +25 -0
  110. data/spec/metrics_spec.rb +62 -0
  111. data/spec/pdf_object_spec.rb +112 -0
  112. data/spec/png_spec.rb +196 -0
  113. data/spec/reference_spec.rb +42 -0
  114. data/spec/spec_helper.rb +23 -0
  115. data/spec/table_spec.rb +179 -0
  116. data/spec/text_spec.rb +135 -0
  117. metadata +181 -0
@@ -0,0 +1,113 @@
1
+ module Prawn
2
+ class Document
3
+
4
+ # This module exposes a few low-level PDF features for those who want
5
+ # to extend Prawn's core functionality. If you are not comfortable with
6
+ # low level PDF functionality as defined by Adobe's specification, chances
7
+ # are you won't need anything you find here.
8
+ #
9
+ module Internals
10
+ # Creates a new Prawn::Reference and adds it to the Document's object
11
+ # list. The +data+ argument is anything that Prawn::PdfObject() can convert.
12
+ def ref(data)
13
+ @objects.push(Prawn::Reference.new(@objects.size + 1, data)).last
14
+ end
15
+
16
+ # Appends a raw string to the current page content.
17
+ #
18
+ # # Raw line drawing example:
19
+ # x1,y1,x2,y2 = 100,500,300,550
20
+ # pdf.add_content("%.3f %.3f m" % [ x1, y1 ]) # move
21
+ # pdf.add_content("%.3f %.3f l" % [ x2, y2 ]) # draw path
22
+ # pdf.add_content("S") # stroke
23
+ #
24
+ def add_content(str)
25
+ @page_content << str << "\n"
26
+ end
27
+
28
+ # Add a new type to the current pages ProcSet
29
+ #
30
+ def proc_set(*types)
31
+ @current_page.data[:ProcSet] ||= ref([])
32
+ @current_page.data[:ProcSet].data |= types
33
+ end
34
+
35
+ # The Resources dictionary for the current page
36
+ #
37
+ def page_resources
38
+ @current_page.data[:Resources] ||= {}
39
+ end
40
+
41
+ # The Font dictionary for the current page
42
+ #
43
+ def page_fonts
44
+ page_resources[:Font] ||= {}
45
+ end
46
+
47
+ # The XObject dictionary for the current page
48
+ def page_xobjects
49
+ page_resources[:XObject] ||= {}
50
+ end
51
+
52
+ # The Name dictionary (PDF spec 3.6.3) for this document. It is
53
+ # lazily initialized, so that documents that do not need a name
54
+ # dictionary do not incur the additional overhead.
55
+ def names
56
+ @root.data[:Names] ||= ref(:Type => :Names)
57
+ end
58
+
59
+ private
60
+
61
+ def finish_page_content
62
+ @header.draw if @header
63
+ @footer.draw if @footer
64
+ add_content "Q"
65
+ @page_content.compress_stream if compression_enabled?
66
+ @page_content.data[:Length] = @page_content.stream.size
67
+ end
68
+
69
+ # Write out the PDF Header, as per spec 3.4.1
70
+ def render_header(output)
71
+ # pdf version
72
+ output << "%PDF-1.3\n"
73
+
74
+ # 4 binary chars, as recommended by the spec
75
+ output << "\xFF\xFF\xFF\xFF\n"
76
+ end
77
+
78
+ # Write out the PDF Body, as per spec 3.4.2
79
+ def render_body(output)
80
+ @objects.each do |ref|
81
+ ref.offset = output.size
82
+ output << ref.object
83
+ end
84
+ end
85
+
86
+ # Write out the PDF Cross Reference Table, as per spec 3.4.3
87
+ def render_xref(output)
88
+ @xref_offset = output.size
89
+ output << "xref\n"
90
+ output << "0 #{@objects.size + 1}\n"
91
+ output << "0000000000 65535 f \n"
92
+ @objects.each do |ref|
93
+ output.printf("%010d", ref.offset)
94
+ output << " 00000 n \n"
95
+ end
96
+ end
97
+
98
+ # Write out the PDF Body, as per spec 3.4.4
99
+ def render_trailer(output)
100
+ trailer_hash = {:Size => @objects.size + 1,
101
+ :Root => @root,
102
+ :Info => @info}
103
+
104
+ output << "trailer\n"
105
+ output << Prawn::PdfObject(trailer_hash) << "\n"
106
+ output << "startxref\n"
107
+ output << @xref_offset << "\n"
108
+ output << "%%EOF"
109
+ end
110
+
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,79 @@
1
+ # encoding: utf-8
2
+
3
+ # page_geometry.rb : Describes PDF page geometries
4
+ #
5
+ # Copyright April 2008, Gregory Brown. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+ module Prawn
10
+ class Document
11
+ module PageGeometry
12
+
13
+ # Dimensions pulled from PDF::Writer, rubyforge.org/projects/ruby-pdf
14
+ SIZES = { "4A0" => [4767.87, 6740.79],
15
+ "2A0" => [3370.39, 4767.87],
16
+ "A0" => [2383.94, 3370.39],
17
+ "A1" => [1683.78, 2383.94],
18
+ "A2" => [1190.55, 1683.78],
19
+ "A3" => [841.89, 1190.55],
20
+ "A4" => [595.28, 841.89],
21
+ "A5" => [419.53, 595.28],
22
+ "A6" => [297.64, 419.53],
23
+ "A7" => [209.76, 297.64],
24
+ "A8" => [147.40, 209.76],
25
+ "A9" => [104.88, 147.40],
26
+ "A10" => [73.70, 104.88],
27
+ "B0" => [2834.65, 4008.19],
28
+ "B1" => [2004.09, 2834.65],
29
+ "B2" => [1417.32, 2004.09],
30
+ "B3" => [1000.63, 1417.32],
31
+ "B4" => [708.66, 1000.63],
32
+ "B5" => [498.90, 708.66],
33
+ "B6" => [354.33, 498.90],
34
+ "B7" => [249.45, 354.33],
35
+ "B8" => [175.75, 249.45],
36
+ "B9" => [124.72, 175.75],
37
+ "B10" => [87.87, 124.72],
38
+ "C0" => [2599.37, 3676.54],
39
+ "C1" => [1836.85, 2599.37],
40
+ "C2" => [1298.27, 1836.85],
41
+ "C3" => [918.43, 1298.27],
42
+ "C4" => [649.13, 918.43],
43
+ "C5" => [459.21, 649.13],
44
+ "C6" => [323.15, 459.21],
45
+ "C7" => [229.61, 323.15],
46
+ "C8" => [161.57, 229.61],
47
+ "C9" => [113.39, 161.57],
48
+ "C10" => [79.37, 113.39],
49
+ "RA0" => [2437.80, 3458.27],
50
+ "RA1" => [1729.13, 2437.80],
51
+ "RA2" => [1218.90, 1729.13],
52
+ "RA3" => [864.57, 1218.90],
53
+ "RA4" => [609.45, 864.57],
54
+ "SRA0" => [2551.18, 3628.35],
55
+ "SRA1" => [1814.17, 2551.18],
56
+ "SRA2" => [1275.59, 1814.17],
57
+ "SRA3" => [907.09, 1275.59],
58
+ "SRA4" => [637.80, 907.09],
59
+ "EXECUTIVE" => [521.86, 756.00],
60
+ "FOLIO" => [612.00, 936.00],
61
+ "LEGAL" => [612.00, 1008.00],
62
+ "LETTER" => [612.00, 792.00],
63
+ "TABLOID" => [792.00, 1224.00] }
64
+
65
+ def page_dimensions #:nodoc:
66
+ coords = SIZES[page_size] || page_size
67
+ [0,0] + case(page_layout)
68
+ when :portrait
69
+ coords
70
+ when :landscape
71
+ coords.reverse
72
+ else
73
+ raise Prawn::Errors::InvalidPageLayout,
74
+ "Layout must be either :portrait or :landscape"
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,47 @@
1
+ module Prawn
2
+ class Document
3
+ # A span is a special purpose bounding box that allows a column of
4
+ # elements to be positioned relative to the margin_box.
5
+ #
6
+ # Arguments:
7
+ # +width+:: The width of the column in PDF points
8
+ #
9
+ # Options:
10
+ # <tt>:position</tt>:: One of :left, :center, :right or an x offset
11
+ #
12
+ # This method is typically used for flowing a column of text from one
13
+ # page to the next.
14
+ #
15
+ # span(350, :position => :center) do
16
+ # text "Here's some centered text in a 350 point column. " * 100
17
+ # end
18
+ #
19
+ def span(width, options={})
20
+ Prawn.verify_options [:position], options
21
+ original_position = self.y
22
+
23
+ # FIXME: How many effing times do I want to write this same code?
24
+ left_boundary = case(options[:position] || :left)
25
+ when :left
26
+ margin_box.absolute_left
27
+ when :center
28
+ margin_box.absolute_left + margin_box.width / 2.0 - width /2.0
29
+ when :right
30
+ margin_box.absolute_right - width
31
+ when Numeric
32
+ margin_box.absolute_left + options[:position]
33
+ else
34
+ raise ArgumentError, "Invalid option for :position"
35
+ end
36
+
37
+ # we need to bust out of whatever nested bounding boxes we're in.
38
+ canvas do
39
+ bounding_box([left_boundary,
40
+ margin_box.absolute_top], :width => width) do
41
+ self.y = original_position
42
+ yield
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,350 @@
1
+ # encoding: utf-8
2
+ #
3
+ # table.rb : Simple table drawing functionality
4
+ #
5
+ # Copyright June 2008, Gregory Brown. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+ module Prawn
10
+ class Document
11
+
12
+ # Builds and renders a Document::Table object from raw data.
13
+ # For details on the options that can be passed, see
14
+ # Document::Table.new
15
+ #
16
+ # data = [["Gregory","Brown"],["James","Healy"],["Jia","Wu"]]
17
+ #
18
+ # Prawn::Document.generate("table.pdf") do
19
+ #
20
+ # # Default table, without headers
21
+ # table(data)
22
+ #
23
+ # # Default table with headers
24
+ # table data, :headers => ["First Name", "Last Name"]
25
+ #
26
+ # # Very close to PDF::Writer's default SimpleTable output
27
+ # table data, :headers => ["First Name", "Last Name"],
28
+ # :font_size => 10,
29
+ # :vertical_padding => 2,
30
+ # :horizontal_padding => 5,
31
+ # :position => :center,
32
+ # :row_colors => :pdf_writer,
33
+ #
34
+ # # Grid border style with explicit column widths.
35
+ # table data, :border_style => :grid,
36
+ # :widths => { 0 => 100, 1 => 150 }
37
+ #
38
+ # end
39
+ #
40
+ # Will raise <tt>Prawn::Errors::EmptyTable</tt> given
41
+ # a nil or empty <tt>data</tt> paramater.
42
+ #
43
+ def table(data,options={})
44
+ if data.nil? || data.empty?
45
+ raise Prawn::Errors::EmptyTable,
46
+ "data must be a non-empty, non-nil, two dimensional array of Prawn::Cells or strings"
47
+ end
48
+ Prawn::Document::Table.new(data,self,options).draw
49
+ end
50
+
51
+ # This class implements simple PDF table generation.
52
+ #
53
+ # Prawn tables have the following features:
54
+ #
55
+ # * Can be generated with or without headers
56
+ # * Can tweak horizontal and vertical padding of text
57
+ # * Minimal styling support (borders / row background colors)
58
+ # * Can be positioned by bounding boxes (left/center aligned) or an
59
+ # absolute x position
60
+ # * Automated page-breaking as needed
61
+ # * Column widths can be calculated automatically or defined explictly on a
62
+ # column by column basis
63
+ # * Text alignment can be set for the whole table or by column
64
+ #
65
+ # The current implementation is a bit barebones, but covers most of the
66
+ # basic needs for PDF table generation. If you have feature requests,
67
+ # please share them at: http://groups.google.com/group/prawn-ruby
68
+ #
69
+ # Tables will be revisited before the end of the Ruby Mendicant project and
70
+ # the most commonly needed functionality will likely be added.
71
+ #
72
+ class Table
73
+
74
+ include Prawn::Configurable
75
+
76
+ attr_reader :col_widths # :nodoc:
77
+
78
+ NUMBER_PATTERN = /^-?(?:0|[1-9]\d*)(?:\.\d+(?:[eE][+-]?\d+)?)?$/ #:nodoc:
79
+
80
+ # Creates a new Document::Table object. This is generally called
81
+ # indirectly through Document#table but can also be used explictly.
82
+ #
83
+ # The <tt>data</tt> argument is a two dimensional array of strings,
84
+ # organized by row, e.g. [["r1-col1","r1-col2"],["r2-col2","r2-col2"]].
85
+ # As with all Prawn text drawing operations, strings must be UTF-8 encoded.
86
+ #
87
+ # The following options are available for customizing your tables, with
88
+ # defaults shown in [] at the end of each description.
89
+ #
90
+ # <tt>:font_size</tt>:: The font size for the text cells . [12]
91
+ # <tt>:horizontal_padding</tt>:: The horizontal cell padding in PDF points [5]
92
+ # <tt>:vertical_padding</tt>:: The vertical cell padding in PDF points [5]
93
+ # <tt>:padding</tt>:: Horizontal and vertical cell padding (overrides both)
94
+ # <tt>:border_width</tt>:: With of border lines in PDF points [1]
95
+ # <tt>:border_style</tt>:: If set to :grid, fills in all borders. If set to :top_and_bottom, only draws horizontal lines. Otherwise, borders are drawn on columns only, not rows
96
+ # <tt>:border_header_style</tt>:: Applies the selected style to every header cell. Defaults to :bottom_only
97
+ # <tt>:position</tt>:: One of <tt>:left</tt>, <tt>:center</tt> or <tt>n</tt>, where <tt>n</tt> is an x-offset from the left edge of the current bounding box
98
+ # <tt>:widths:</tt> A hash of indices and widths in PDF points. E.g. <tt>{ 0 => 50, 1 => 100 }</tt>
99
+ # <tt>:row_colors</tt>:: An array of row background colors which are used cyclicly.
100
+ # <tt>:align</tt>:: Alignment of text in columns, for entire table (<tt>:center</tt>) or by column (<tt>{ 0 => :left, 1 => :center}</tt>)
101
+ # <tt>:align_headers</tt>:: Alignment of header text. Specify for entire header (<tt>:left</tt>) or by column (<tt>{ 0 => :right, 1 => :left}</tt>). If omitted, the header alignment is the same as the column alignment.
102
+ # <tt>:minimum_rows</tt>:: The minimum rows to display on a page, including header.
103
+ #
104
+ # Row colors are specified as html encoded values, e.g.
105
+ # ["ffffff","aaaaaa","ccaaff"]. You can also specify
106
+ # <tt>:row_colors => :pdf_writer</tt> if you wish to use the default color
107
+ # scheme from the PDF::Writer library.
108
+ #
109
+ # See Document#table for typical usage, as directly using this class is
110
+ # not recommended unless you know why you want to do it.
111
+ #
112
+ def initialize(data, document,options={})
113
+ unless data.all? { |e| Array === e }
114
+ raise Prawn::Errors::InvalidTableData,
115
+ "data must be a two dimensional array of Prawn::Cells or strings"
116
+ end
117
+
118
+ @data = data
119
+ @document = document
120
+
121
+ Prawn.verify_options [:font_size, :border_style, :border_header_style, :border_width,
122
+ :position, :headers, :row_colors, :align, :align_headers, :header_text_color, :border_color,
123
+ :horizontal_padding, :vertical_padding, :padding, :widths,
124
+ :header_color ], options
125
+
126
+ configuration.update(options)
127
+
128
+ if padding = options[:padding]
129
+ C(:horizontal_padding => padding, :vertical_padding => padding)
130
+ end
131
+
132
+ if options[:row_colors] == :pdf_writer
133
+ C(:row_colors => ["ffffff","cccccc"])
134
+ end
135
+
136
+ if options[:row_colors]
137
+ C(:original_row_colors => C(:row_colors))
138
+ end
139
+
140
+ calculate_column_widths(options[:widths])
141
+ end
142
+
143
+ attr_reader :col_widths #:nodoc:
144
+
145
+ # Width of the table in PDF points
146
+ #
147
+ def width
148
+ @col_widths.inject(0) { |s,r| s + r }
149
+ end
150
+
151
+ # Draws the table onto the PDF document
152
+ #
153
+ def draw
154
+ @parent_bounds = @document.bounds
155
+ case C(:position)
156
+ when :center
157
+ x = (@document.bounds.width - width) / 2.0
158
+ dy = @document.bounds.absolute_top - @document.y
159
+ @document.bounding_box [x, @parent_bounds.top], :width => width do
160
+ @document.move_down(dy)
161
+ generate_table
162
+ end
163
+ when Numeric
164
+ x, y = C(:position), @document.y - @document.bounds.absolute_bottom
165
+ @document.bounding_box([x,y], :width => width) { generate_table }
166
+ else
167
+ generate_table
168
+ end
169
+ end
170
+
171
+ private
172
+
173
+ def default_configuration
174
+ { :font_size => 12,
175
+ :border_width => 1,
176
+ :position => :left,
177
+ :horizontal_padding => 5,
178
+ :vertical_padding => 5 }
179
+ end
180
+
181
+ def calculate_column_widths(manual_widths=nil)
182
+ @col_widths = [0] * @data[0].length
183
+ renderable_data.each do |row|
184
+ row.each_with_index do |cell,i|
185
+ length = cell.to_s.lines.map { |e|
186
+ @document.font.metrics.string_width(e,C(:font_size)) }.max.to_f +
187
+ 2*C(:horizontal_padding)
188
+ @col_widths[i] = length.ceil if length > @col_widths[i]
189
+ end
190
+ end
191
+
192
+ manual_widths.each { |k,v| @col_widths[k] = v } if manual_widths
193
+ end
194
+
195
+ def renderable_data
196
+ C(:headers) ? [C(:headers)] + @data : @data
197
+ end
198
+
199
+ def generate_table
200
+ page_contents = []
201
+ y_pos = @document.y
202
+
203
+ @document.font.size C(:font_size) do
204
+ renderable_data.each_with_index do |row,index|
205
+ c = Prawn::Graphics::CellBlock.new(@document)
206
+
207
+ col_index = 0
208
+ row.each do |e|
209
+ case C(:align)
210
+ when Hash
211
+ align = C(:align)[col_index]
212
+ else
213
+ align = C(:align)
214
+ end
215
+
216
+
217
+ align ||= e.to_s =~ NUMBER_PATTERN ? :right : :left
218
+
219
+ case e
220
+ when Prawn::Graphics::Cell
221
+ e.document = @document
222
+ e.width = @col_widths[col_index]
223
+ e.horizontal_padding = C(:horizontal_padding)
224
+ e.vertical_padding = C(:vertical_padding)
225
+ e.border_width = C(:border_width)
226
+ e.border_style = :sides
227
+ e.align = align
228
+ c << e
229
+ else
230
+ text = e.is_a?(Hash) ? e[:text] : e.to_s
231
+ width = if e.is_a?(Hash) && e.has_key?(:colspan)
232
+ @col_widths.slice(col_index, e[:colspan]).inject { |sum, width| sum + width }
233
+ else
234
+ @col_widths[col_index]
235
+ end
236
+
237
+ c << Prawn::Graphics::Cell.new(
238
+ :document => @document,
239
+ :text => text,
240
+ :width => width,
241
+ :horizontal_padding => C(:horizontal_padding),
242
+ :vertical_padding => C(:vertical_padding),
243
+ :border_width => C(:border_width),
244
+ :border_style => :sides,
245
+ :align => align )
246
+ end
247
+
248
+ col_index += (e.is_a?(Hash) && e.has_key?(:colspan)) ? e[:colspan] : 1
249
+ end
250
+
251
+ bbox = @parent_bounds.stretchy? ? @document.margin_box : @parent_bounds
252
+ if c.height > y_pos - bbox.absolute_bottom
253
+ if C(:headers) && page_contents.length == 1
254
+ @document.start_new_page
255
+ y_pos = @document.y
256
+ else
257
+ draw_page(page_contents)
258
+ @document.start_new_page
259
+ if C(:headers) && page_contents.any?
260
+ page_contents = [page_contents[0]]
261
+ y_pos = @document.y - page_contents[0].height
262
+ else
263
+ page_contents = []
264
+ y_pos = @document.y
265
+ end
266
+ end
267
+ end
268
+
269
+ page_contents << c
270
+
271
+ y_pos -= c.height
272
+
273
+ if index == renderable_data.length - 1
274
+ draw_page(page_contents)
275
+ end
276
+
277
+ end
278
+ end
279
+ end
280
+
281
+ def draw_page(contents)
282
+ return if contents.empty?
283
+
284
+ # TODO - this will eventually be made redundant
285
+ if C(:border_style) == :underline_header
286
+ contents.each { |e| e.border_style = :none }
287
+ contents.first.border_style = :bottom_only if C(:headers) && C(:header_border_style).nil?
288
+
289
+
290
+ elsif C(:border_style) == :grid || contents.length == 1
291
+ contents.each { |e| e.border_style = :all }
292
+
293
+ elsif C(:border_style) == :top_and_bottom
294
+ contents.each { |e| e.border_style = :top_and_bottom }
295
+
296
+ else
297
+ contents.first.border_style = C(:headers) ? :all : :no_bottom
298
+ contents.last.border_style = :no_top
299
+ end
300
+
301
+ if C(:headers)
302
+
303
+ if C(:header_border_style)
304
+ contents.first.border_style = C(:header_border_style)
305
+ else
306
+ contents.first.border_style = :bottom_only
307
+ end
308
+
309
+
310
+ contents.first.cells.each_with_index do |e,i|
311
+ if C(:align_headers)
312
+ case C(:align_headers)
313
+ when Hash
314
+ align = C(:align_headers)[i]
315
+ else
316
+ align = C(:align_headers)
317
+ end
318
+ end
319
+ e.align = align if align
320
+ e.text_color = C(:header_text_color) if C(:header_text_color)
321
+ e.background_color = C(:header_color) if C(:header_color)
322
+ end
323
+ end
324
+
325
+ contents.each do |x|
326
+ unless x.background_color
327
+ x.background_color = next_row_color if C(:row_colors)
328
+ end
329
+ x.border_color = C(:border_color) if C(:border_color)
330
+
331
+ x.draw
332
+ end
333
+
334
+ reset_row_colors
335
+ end
336
+
337
+
338
+ def next_row_color
339
+ color = C(:row_colors).shift
340
+ C(:row_colors).push(color)
341
+ color
342
+ end
343
+
344
+ def reset_row_colors
345
+ C(:row_colors => C(:original_row_colors).dup) if C(:row_colors)
346
+ end
347
+
348
+ end
349
+ end
350
+ end