prawn 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/Rakefile +3 -1
  2. data/data/fonts/Action Man.dfont +0 -0
  3. data/examples/general/measurement_units.rb +2 -2
  4. data/examples/graphics/image_flow.rb +2 -2
  5. data/examples/graphics/stroke_bounds.rb +1 -1
  6. data/examples/m17n/win_ansi_charset.rb +3 -3
  7. data/examples/text/dfont.rb +49 -0
  8. data/examples/text/flowing_text_with_header_and_footer.rb +2 -48
  9. data/examples/text/font_calculations.rb +7 -6
  10. data/examples/text/font_size.rb +4 -4
  11. data/examples/text/text_flow.rb +1 -1
  12. data/lib/prawn.rb +6 -3
  13. data/lib/prawn/compatibility.rb +12 -17
  14. data/lib/prawn/document.rb +10 -10
  15. data/lib/prawn/document/internals.rb +8 -3
  16. data/lib/prawn/document/text.rb +39 -57
  17. data/lib/prawn/document/text/box.rb +1 -2
  18. data/lib/prawn/document/text/wrapping.rb +59 -0
  19. data/lib/prawn/errors.rb +0 -8
  20. data/lib/prawn/font.rb +192 -277
  21. data/lib/prawn/font/afm.rb +199 -0
  22. data/lib/prawn/font/dfont.rb +31 -0
  23. data/lib/prawn/font/ttf.rb +318 -0
  24. data/lib/prawn/graphics.rb +7 -2
  25. data/lib/prawn/images/png.rb +1 -1
  26. data/lib/prawn/reference.rb +7 -4
  27. data/spec/font_spec.rb +154 -61
  28. data/spec/text_spec.rb +47 -6
  29. data/vendor/pdf-inspector/lib/pdf/inspector.rb +1 -1
  30. data/vendor/ttfunk/example.rb +42 -2
  31. data/vendor/ttfunk/lib/ttfunk.rb +96 -42
  32. data/vendor/ttfunk/lib/ttfunk/directory.rb +17 -0
  33. data/vendor/ttfunk/lib/ttfunk/encoding/mac_roman.rb +88 -0
  34. data/vendor/ttfunk/lib/ttfunk/encoding/windows_1252.rb +69 -0
  35. data/vendor/ttfunk/lib/ttfunk/reader.rb +44 -0
  36. data/vendor/ttfunk/lib/ttfunk/resource_file.rb +78 -0
  37. data/vendor/ttfunk/lib/ttfunk/subset.rb +18 -0
  38. data/vendor/ttfunk/lib/ttfunk/subset/base.rb +141 -0
  39. data/vendor/ttfunk/lib/ttfunk/subset/mac_roman.rb +46 -0
  40. data/vendor/ttfunk/lib/ttfunk/subset/unicode.rb +48 -0
  41. data/vendor/ttfunk/lib/ttfunk/subset/unicode_8bit.rb +63 -0
  42. data/vendor/ttfunk/lib/ttfunk/subset/windows_1252.rb +51 -0
  43. data/vendor/ttfunk/lib/ttfunk/subset_collection.rb +72 -0
  44. data/vendor/ttfunk/lib/ttfunk/table.rb +37 -18
  45. data/vendor/ttfunk/lib/ttfunk/table/cmap.rb +24 -84
  46. data/vendor/ttfunk/lib/ttfunk/table/cmap/format00.rb +54 -0
  47. data/vendor/ttfunk/lib/ttfunk/table/cmap/format04.rb +126 -0
  48. data/vendor/ttfunk/lib/ttfunk/table/cmap/subtable.rb +79 -0
  49. data/vendor/ttfunk/lib/ttfunk/table/glyf.rb +64 -0
  50. data/vendor/ttfunk/lib/ttfunk/table/glyf/compound.rb +81 -0
  51. data/vendor/ttfunk/lib/ttfunk/table/glyf/simple.rb +37 -0
  52. data/vendor/ttfunk/lib/ttfunk/table/head.rb +38 -19
  53. data/vendor/ttfunk/lib/ttfunk/table/hhea.rb +35 -21
  54. data/vendor/ttfunk/lib/ttfunk/table/hmtx.rb +40 -13
  55. data/vendor/ttfunk/lib/ttfunk/table/kern.rb +69 -38
  56. data/vendor/ttfunk/lib/ttfunk/table/kern/format0.rb +62 -0
  57. data/vendor/ttfunk/lib/ttfunk/table/loca.rb +43 -0
  58. data/vendor/ttfunk/lib/ttfunk/table/maxp.rb +34 -11
  59. data/vendor/ttfunk/lib/ttfunk/table/name.rb +109 -42
  60. data/vendor/ttfunk/lib/ttfunk/table/os2.rb +78 -0
  61. data/vendor/ttfunk/lib/ttfunk/table/post.rb +91 -0
  62. data/vendor/ttfunk/lib/ttfunk/table/post/format10.rb +43 -0
  63. data/vendor/ttfunk/lib/ttfunk/table/post/format20.rb +35 -0
  64. data/vendor/ttfunk/lib/ttfunk/table/post/format25.rb +23 -0
  65. data/vendor/ttfunk/lib/ttfunk/table/post/format30.rb +17 -0
  66. data/vendor/ttfunk/lib/ttfunk/table/post/format40.rb +17 -0
  67. data/vendor/ttfunk/lib/ttfunk/table/simple.rb +14 -0
  68. metadata +54 -25
  69. data/examples/table/addressbook.csv +0 -6
  70. data/examples/table/cell.rb +0 -40
  71. data/examples/table/currency.csv +0 -1834
  72. data/examples/table/fancy_table.rb +0 -62
  73. data/examples/table/ruport_formatter.rb +0 -53
  74. data/examples/table/table.rb +0 -51
  75. data/examples/table/table_alignment.rb +0 -18
  76. data/examples/table/table_border_color.rb +0 -17
  77. data/examples/table/table_colspan.rb +0 -19
  78. data/examples/table/table_header_color.rb +0 -19
  79. data/examples/table/table_header_underline.rb +0 -15
  80. data/lib/prawn/document/table.rb +0 -338
  81. data/lib/prawn/font/cmap.rb +0 -59
  82. data/lib/prawn/font/metrics.rb +0 -378
  83. data/lib/prawn/font/wrapping.rb +0 -47
  84. data/lib/prawn/graphics/cell.rb +0 -264
  85. data/spec/metrics_spec.rb +0 -62
  86. data/spec/table_spec.rb +0 -179
  87. data/vendor/ttfunk/lib/ttfunk/table/directory.rb +0 -25
@@ -1,62 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- # Demonstrates various table and cell features.
4
- #
5
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
6
- require "prawn"
7
- require "rubygems"
8
-
9
- headers, body = nil, nil
10
-
11
- ruby_18 do
12
- require "fastercsv"
13
- headers, *body = FasterCSV.read("#{Prawn::BASEDIR}/examples/table/addressbook.csv")
14
- end
15
-
16
- ruby_19 do
17
- require "csv"
18
- headers, *body = CSV.read("#{Prawn::BASEDIR}/examples/table/addressbook.csv",
19
- :encoding => "utf-8")
20
- end
21
-
22
- Prawn::Document.generate("fancy_table.pdf", :page_layout => :landscape) do
23
-
24
- #font "#{Prawn::BASEDIR}/data/fonts/DejaVuSans.ttf"
25
-
26
- mask(:y) { table body, :headers => headers,
27
- :align => :center,
28
- :border_style => :grid }
29
-
30
- table [["This is", "A Test" ],
31
- [ Prawn::Graphics::Cell.new( :text => "Of tables",
32
- :background_color => "ffccff" ),
33
- "Drawn Side"], ["By side", "and stuff" ]],
34
- :position => 600,
35
- :headers => ["Col A", "Col B"],
36
- :border_width => 1,
37
- :vertical_padding => 5,
38
- :horizontal_padding => 3,
39
- :font_size => 10,
40
- :row_colors => :pdf_writer,
41
- :widths => { 1 => 50 }
42
-
43
- move_down 150
44
-
45
- table [%w[1 2 3],%w[4 5 6],%w[7 8 9]],
46
- :position => :center,
47
- :border_width => 0,
48
- :font_size => 40
49
-
50
- cell [500,300],
51
- :text => "This free flowing textbox shows how you can use Prawn's "+
52
- "cells outside of a table with ease. Think of a 'cell' as " +
53
- "simply a limited purpose bounding box that is meant for laying " +
54
- "out blocks of text and optionally placing a border around it",
55
- :width => 225, :padding => 10, :border_width => 2
56
-
57
- font.size = 24
58
- cell [50,75],
59
- :text => "This document demonstrates a number of Prawn's table features",
60
- :border_style => :no_top, # :all, :no_bottom, :sides
61
- :horizontal_padding => 5
62
- end
@@ -1,53 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- # A simple proof of concept of building a Prawn based PDF formatter for
4
- # Ruport tables. Requires Ruby Reports to run.
5
- #
6
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
7
- require "prawn"
8
-
9
- ruby_18 do
10
- require "rubygems"
11
- require "ruport"
12
-
13
- module Ruport
14
- class Formatter
15
- class PrawnPDF < Ruport::Formatter
16
- renders :pdf, :for => Ruport::Controller::Table
17
-
18
- def document
19
- @document ||= (options.document || Prawn::Document.new)
20
- end
21
-
22
- def table_body
23
- data.map { |e| e.to_a }
24
- end
25
-
26
- build :table_header do
27
- @headers = options.headers || data.column_names
28
- end
29
-
30
- build :table_body do
31
- document.table table_body,
32
- :headers => @headers,
33
- :row_colors => :pdf_writer,
34
- :position => :center,
35
- :font_size => 10,
36
- :vertical_padding => 2,
37
- :horizontal_padding => 5
38
- end
39
-
40
- def finalize
41
- output << document.render
42
- end
43
-
44
- end
45
- end
46
- end
47
-
48
- if __FILE__ == $PROGRAM_NAME
49
- t = Table("#{Prawn::BASEDIR}/examples/table/addressbook.csv")
50
- headers = t.column_names.map { |c| c.capitalize }
51
- t.save_as "addressbook_ruport.pdf", :headers => headers
52
- end
53
- end
@@ -1,51 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- # Generates a couple simple tables, including some UTF-8 text cells.
4
- # Although this does not show all of the options available to table, the most
5
- # common are used here. See fancy_table.rb for a more comprehensive example.
6
- #
7
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
8
- require "prawn"
9
-
10
- Prawn::Document.generate("table.pdf") do
11
- font "#{Prawn::BASEDIR}/data/fonts/DejaVuSans.ttf"
12
- table [["ὕαλον ϕαγεῖν", "baaar", "1" ],
13
- ["This is","a sample", "2" ],
14
- ["Table", "dont\ncha\nknow?", "3" ],
15
- [ "It", "Rules", "4" ],
16
- [ "It", "Rules", "4" ],
17
- [ "It", "Rules", "4123231" ],
18
- [ "It", "Rules", "22.5" ],
19
- [ "It", "Rules", "4" ],
20
- [ "It", "Rules", "4" ],
21
- [ "It", "Rules", "4" ],
22
- [ "It", "Rules", "4" ],
23
- [ "It", "Rules", "4" ],
24
- [ "It", "Rules\nwith an iron fist", "x" ],
25
- [ "It", "Rules", "4" ],
26
- [ "It", "Rules", "4" ],
27
- [ "It", "Rules", "4" ],
28
- [ "It", "Rules", "4" ],
29
- [ "It", "Rules", "4" ],
30
- [ "It", "Rules", "4" ],
31
- [ "It", "Rules", "4" ],
32
- [ "It", "Rules", "4" ],
33
- [ "It", "Rules", "4" ]],
34
-
35
- :font_size => 24,
36
- :horizontal_padding => 10,
37
- :vertical_padding => 3,
38
- :border_width => 2,
39
- :position => :center,
40
- :headers => ["Column A","Column B","#"],
41
- :align => {1 => :center},
42
- :align_headers => :center
43
-
44
- text "This should appear in the original font size, just below the table"
45
- move_down 10
46
-
47
- table [[ "Wide", "columns", "streeetch"],
48
- ["are","mighty fine", "streeeeeeeech"]],
49
- :widths => { 0 => 200, 1 => 250 }, :position => 5
50
-
51
- end
@@ -1,18 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- # Demonstrates the many controls over alignment and positioning in Prawn
4
- # tables.
5
- #
6
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
7
- require "prawn"
8
-
9
- Prawn::Document.generate "table_header_align.pdf" do
10
- table [ ['01/01/2008', 'John Doe', '4.2', '125.00', '525.00'],
11
- ['01/12/2008', 'Jane Doe', '3.2', '75.50', '241.60'] ] * 20,
12
- :position => :center,
13
- :headers => ['Date', 'Employee', 'Hours', 'Rate', 'Total'],
14
- :widths => { 0 => 75, 1 => 100, 2 => 50, 3 => 50, 4 => 50},
15
- :border_style => :grid,
16
- :align => { 0 => :right, 1 => :left, 2 => :right, 3 => :right, 4 => :right },
17
- :align_headers => { 0 => :center, 2 => :left, 3 => :left, 4 => :right }
18
- end
@@ -1,17 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- # Demonstrates how to set the table border color with the :border_color
4
- # attribute.
5
- #
6
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
7
- require "prawn"
8
-
9
- Prawn::Document.generate "table_border_color.pdf" do
10
- table [ ['01/01/2008', 'John Doe', '4.2', '125.00', '525.00'],
11
- ['01/12/2008', 'Jane Doe', '3.2', '75.50', '241.60'] ] * 20,
12
- :position => :center,
13
- :headers => ['Date', 'Employee', 'Hours', 'Rate', 'Total'],
14
- :widths => { 0 => 75, 1 => 100, 2 => 50, 3 => 50, 4 => 50},
15
- :border_style => :grid,
16
- :border_color => "ff0000"
17
- end
@@ -1,19 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- # Demonstrates the use of the :col_span option when using Document#table
4
- #
5
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
6
- require "prawn"
7
-
8
- Prawn::Document.generate "table_colspan.pdf" do
9
- data = [ ['01/01/2008', 'John Doe', '4.2', '125.00', '525.00'],
10
- ['01/12/2008', 'Jane Doe', '3.2', '75.50', '241.60'] ] * 5
11
-
12
- data << [{:text => 'Total', :colspan => 2}, '37.0', '1002.5', '3833']
13
-
14
- table data,
15
- :position => :center,
16
- :headers => ['Date', 'Employee', 'Hours', 'Rate', 'Total'],
17
- :widths => { 0 => 75, 1 => 100, 2 => 50, 3 => 50, 4 => 50},
18
- :border_style => :grid
19
- end
@@ -1,19 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- # Demonstrates explicitly setting the :header_color rather than inferring
4
- # it from :row_colors in Document#table
5
- #
6
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
7
- require "prawn"
8
-
9
- Prawn::Document.generate "table_header_color.pdf" do
10
- table [ ['01/01/2008', 'John Doe', '4.2', '125.00', '525.00'],
11
- ['01/12/2008', 'Jane Doe', '3.2', '75.50', '241.60'] ] * 20,
12
- :position => :center,
13
- :headers => ['Date', 'Employee', 'Hours', 'Rate', 'Total'],
14
- :widths => { 0 => 75, 1 => 100, 2 => 50, 3 => 50, 4 => 50},
15
- :border_style => :grid,
16
- :header_color => 'f07878',
17
- :header_text_color => "990000",
18
- :row_colors => ["FFCCFF","CCFFCC"]
19
- end
@@ -1,15 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- # Demonstrates the :underline_header border style for Document#table.
4
- #
5
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
6
- require "prawn"
7
-
8
- Prawn::Document.generate "table_header_underline.pdf" do
9
- table [ ['01/01/2008', 'John Doe', '4.2', '125.00', '525.00'],
10
- ['01/12/2008', 'Jane Doe', '3.2', '75.50', '241.60'] ] * 5,
11
- :position => :center,
12
- :headers => ['Date', 'Employee', 'Hours', 'Rate', 'Total'],
13
- :widths => { 0 => 75, 1 => 100, 2 => 50, 3 => 50, 4 => 50},
14
- :border_style => :underline_header
15
- end
@@ -1,338 +0,0 @@
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>:headers</tt>:: An array of table headers, either strings or Cells. [Empty]
91
- # <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.
92
- # <tt>:header_text_color</tt>:: Sets the text color of the headers
93
- # <tt>:header_color</tt>:: Manually sets the header color
94
- # <tt>:font_size</tt>:: The font size for the text cells . [12]
95
- # <tt>:horizontal_padding</tt>:: The horizontal cell padding in PDF points [5]
96
- # <tt>:vertical_padding</tt>:: The vertical cell padding in PDF points [5]
97
- # <tt>:padding</tt>:: Horizontal and vertical cell padding (overrides both)
98
- # <tt>:border_width</tt>:: With of border lines in PDF points [1]
99
- # <tt>:border_style</tt>:: If set to :grid, fills in all borders. If set to :underline_header, underline header only. Otherwise, borders are drawn on columns only, not rows
100
- # <tt>:border_color</tt>:: Sets the color of the borders.
101
- # <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
102
- # <tt>:widths:</tt> A hash of indices and widths in PDF points. E.g. <tt>{ 0 => 50, 1 => 100 }</tt>
103
- # <tt>:row_colors</tt>:: An array of row background colors which are used cyclicly.
104
- # <tt>:align</tt>:: Alignment of text in columns, for entire table (<tt>:center</tt>) or by column (<tt>{ 0 => :left, 1 => :center}</tt>)
105
- # <tt>:minimum_rows</tt>:: The minimum rows to display on a page, including header.
106
- #
107
- # Row colors are specified as html encoded values, e.g.
108
- # ["ffffff","aaaaaa","ccaaff"]. You can also specify
109
- # <tt>:row_colors => :pdf_writer</tt> if you wish to use the default color
110
- # scheme from the PDF::Writer library.
111
- #
112
- # See Document#table for typical usage, as directly using this class is
113
- # not recommended unless you know why you want to do it.
114
- #
115
- def initialize(data, document,options={})
116
- unless data.all? { |e| Array === e }
117
- raise Prawn::Errors::InvalidTableData,
118
- "data must be a two dimensional array of Prawn::Cells or strings"
119
- end
120
-
121
- @data = data
122
- @document = document
123
-
124
- Prawn.verify_options [:font_size,:border_style, :border_width,
125
- :position, :headers, :row_colors, :align, :align_headers, :header_text_color, :border_color,
126
- :horizontal_padding, :vertical_padding, :padding, :widths,
127
- :header_color ], options
128
-
129
- configuration.update(options)
130
-
131
- if padding = options[:padding]
132
- C(:horizontal_padding => padding, :vertical_padding => padding)
133
- end
134
-
135
- if options[:row_colors] == :pdf_writer
136
- C(:row_colors => ["ffffff","cccccc"])
137
- end
138
-
139
- if options[:row_colors]
140
- C(:original_row_colors => C(:row_colors))
141
- end
142
-
143
- calculate_column_widths(options[:widths])
144
- end
145
-
146
- attr_reader :col_widths #:nodoc:
147
-
148
- # Width of the table in PDF points
149
- #
150
- def width
151
- @col_widths.inject(0) { |s,r| s + r }
152
- end
153
-
154
- # Draws the table onto the PDF document
155
- #
156
- def draw
157
- @parent_bounds = @document.bounds
158
- case C(:position)
159
- when :center
160
- x = (@document.bounds.width - width) / 2.0
161
- dy = @document.bounds.absolute_top - @document.y
162
- @document.bounding_box [x, @parent_bounds.top], :width => width do
163
- @document.move_down(dy)
164
- generate_table
165
- end
166
- when Numeric
167
- x, y = C(:position), @document.y - @document.bounds.absolute_bottom
168
- @document.bounding_box([x,y], :width => width) { generate_table }
169
- else
170
- generate_table
171
- end
172
- end
173
-
174
- private
175
-
176
- def default_configuration
177
- { :font_size => 12,
178
- :border_width => 1,
179
- :position => :left,
180
- :horizontal_padding => 5,
181
- :vertical_padding => 5 }
182
- end
183
-
184
- def calculate_column_widths(manual_widths=nil)
185
- @col_widths = [0] * @data[0].length
186
- renderable_data.each do |row|
187
- row.each_with_index do |cell,i|
188
- length = cell.to_s.lines.map { |e|
189
- @document.font.metrics.string_width(e,C(:font_size)) }.max.to_f +
190
- 2*C(:horizontal_padding)
191
- @col_widths[i] = length.ceil if length > @col_widths[i]
192
- end
193
- end
194
-
195
- manual_widths.each { |k,v| @col_widths[k] = v } if manual_widths
196
- end
197
-
198
- def renderable_data
199
- C(:headers) ? [C(:headers)] + @data : @data
200
- end
201
-
202
- def generate_table
203
- page_contents = []
204
- y_pos = @document.y
205
-
206
- @document.font.size C(:font_size) do
207
- renderable_data.each_with_index do |row,index|
208
- c = Prawn::Graphics::CellBlock.new(@document)
209
-
210
- col_index = 0
211
- row.each do |e|
212
- case C(:align)
213
- when Hash
214
- align = C(:align)[col_index]
215
- else
216
- align = C(:align)
217
- end
218
-
219
-
220
- align ||= e.to_s =~ NUMBER_PATTERN ? :right : :left
221
-
222
- case e
223
- when Prawn::Graphics::Cell
224
- e.document = @document
225
- e.width = @col_widths[col_index]
226
- e.horizontal_padding = C(:horizontal_padding)
227
- e.vertical_padding = C(:vertical_padding)
228
- e.border_width = C(:border_width)
229
- e.border_style = :sides
230
- e.align = align
231
- c << e
232
- else
233
- text = e.is_a?(Hash) ? e[:text] : e.to_s
234
- width = if e.is_a?(Hash) && e.has_key?(:colspan)
235
- @col_widths.slice(col_index, e[:colspan]).inject { |sum, width| sum + width }
236
- else
237
- @col_widths[col_index]
238
- end
239
-
240
- c << Prawn::Graphics::Cell.new(
241
- :document => @document,
242
- :text => text,
243
- :width => width,
244
- :horizontal_padding => C(:horizontal_padding),
245
- :vertical_padding => C(:vertical_padding),
246
- :border_width => C(:border_width),
247
- :border_style => :sides,
248
- :align => align )
249
- end
250
-
251
- col_index += (e.is_a?(Hash) && e.has_key?(:colspan)) ? e[:colspan] : 1
252
- end
253
-
254
- bbox = @parent_bounds.stretchy? ? @document.margin_box : @parent_bounds
255
- if c.height > y_pos - bbox.absolute_bottom
256
- if C(:headers) && page_contents.length == 1
257
- @document.start_new_page
258
- y_pos = @document.y
259
- else
260
- draw_page(page_contents)
261
- @document.start_new_page
262
- if C(:headers) && page_contents.any?
263
- page_contents = [page_contents[0]]
264
- y_pos = @document.y - page_contents[0].height
265
- else
266
- page_contents = []
267
- y_pos = @document.y
268
- end
269
- end
270
- end
271
-
272
- page_contents << c
273
-
274
- y_pos -= c.height
275
-
276
- if index == renderable_data.length - 1
277
- draw_page(page_contents)
278
- end
279
-
280
- end
281
- end
282
- end
283
-
284
- def draw_page(contents)
285
- return if contents.empty?
286
-
287
- if C(:border_style) == :underline_header
288
- contents.each { |e| e.border_style = :none }
289
- contents.first.border_style = :bottom_only if C(:headers)
290
- elsif C(:border_style) == :grid || contents.length == 1
291
- contents.each { |e| e.border_style = :all }
292
- else
293
- contents.first.border_style = C(:headers) ? :all : :no_bottom
294
- contents.last.border_style = :no_top
295
- end
296
-
297
- if C(:headers)
298
- contents.first.cells.each_with_index do |e,i|
299
- if C(:align_headers)
300
- case C(:align_headers)
301
- when Hash
302
- align = C(:align_headers)[i]
303
- else
304
- align = C(:align_headers)
305
- end
306
- end
307
- e.align = align if align
308
- e.text_color = C(:header_text_color) if C(:header_text_color)
309
- e.background_color = C(:header_color) if C(:header_color)
310
- end
311
- end
312
-
313
- contents.each do |x|
314
- unless x.background_color
315
- x.background_color = next_row_color if C(:row_colors)
316
- end
317
- x.border_color = C(:border_color) if C(:border_color)
318
-
319
- x.draw
320
- end
321
-
322
- reset_row_colors
323
- end
324
-
325
-
326
- def next_row_color
327
- color = C(:row_colors).shift
328
- C(:row_colors).push(color)
329
- color
330
- end
331
-
332
- def reset_row_colors
333
- C(:row_colors => C(:original_row_colors).dup) if C(:row_colors)
334
- end
335
-
336
- end
337
- end
338
- end