prawn-layout 0.1.0 → 0.2.0.1
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.
- data/Rakefile +1 -1
- data/examples/grid/simple_grid.rb +23 -0
- data/examples/page_layout/flowing_text_with_header_and_footer.rb +39 -0
- data/examples/page_layout/lazy_bounding_boxes.rb +30 -0
- data/examples/page_layout/padded_box.rb +26 -0
- data/examples/table/cell.rb +2 -2
- data/lib/prawn/layout.rb +3 -1
- data/lib/prawn/layout/grid.rb +238 -0
- data/lib/prawn/layout/page.rb +116 -0
- data/lib/prawn/table.rb +25 -9
- data/lib/prawn/table/cell.rb +14 -3
- data/spec/grid_spec.rb +61 -0
- data/spec/page_layout_spec.rb +41 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/table_spec.rb +36 -8
- metadata +15 -8
data/Rakefile
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
|
4
|
+
require "rubygems"
|
5
|
+
require "prawn"
|
6
|
+
require "prawn/layout"
|
7
|
+
|
8
|
+
Prawn::Document.generate('simple_grid.pdf') do |p|
|
9
|
+
p.define_grid(:columns => 5, :rows => 8, :gutter => 10)
|
10
|
+
|
11
|
+
p.grid.rows.times do |i|
|
12
|
+
p.grid.columns.times do |j|
|
13
|
+
b = p.grid(i,j)
|
14
|
+
p.bounding_box b.top_left, :width => b.width, :height => b.height do
|
15
|
+
p.text b.name
|
16
|
+
p.stroke do
|
17
|
+
p.rectangle(p.bounds.top_left, b.width, b.height)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Multi-faceted example that demonstrates a document flowing between header
|
4
|
+
# and footer regions. At the moment, headers and footers in Prawn are run
|
5
|
+
# using the current font settings (among other things), for each page. This
|
6
|
+
# means that it is important to non-destructively set your desired styling
|
7
|
+
# within your headers and footers, as shown below.
|
8
|
+
#
|
9
|
+
# Future versions of Prawn may make this more convenient somehow.
|
10
|
+
#
|
11
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
|
12
|
+
require "rubygems"
|
13
|
+
require "prawn"
|
14
|
+
require "prawn/layout"
|
15
|
+
|
16
|
+
Prawn::Document.generate("flow_with_headers_and_footers.pdf") do
|
17
|
+
|
18
|
+
header margin_box.top_left do
|
19
|
+
font "Helvetica" do
|
20
|
+
text "Here's My Fancy Header", :size => 25, :align => :center
|
21
|
+
stroke_horizontal_rule
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
footer [margin_box.left, margin_box.bottom + 25] do
|
26
|
+
font "Helvetica" do
|
27
|
+
stroke_horizontal_rule
|
28
|
+
text "And here's a sexy footer", :size => 16
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
bounding_box([bounds.left, bounds.top - 50],
|
33
|
+
:width => bounds.width, :height => bounds.height - 100) do
|
34
|
+
text "this is some flowing text " * 200
|
35
|
+
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This example demonstrates Document#lazy_bounding_box, which is used for
|
4
|
+
# storing a set of drawing instructions to be executed later. This is used
|
5
|
+
# for header and footer support in Prawn, and can be used for repeating page
|
6
|
+
# elements in general.
|
7
|
+
#
|
8
|
+
# Note that once a lazy bounding box is positioned, it calculates its anchor
|
9
|
+
# relative to its parent bounding box. It will be positioned at this exact
|
10
|
+
# location each time it is redrawn, regardless of the bounds
|
11
|
+
# LazyBoundingBox#draw is in.
|
12
|
+
#
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
|
14
|
+
require "rubygems"
|
15
|
+
require "prawn"
|
16
|
+
require "prawn/layout"
|
17
|
+
|
18
|
+
file = "lazy_bounding_boxes.pdf"
|
19
|
+
Prawn::Document.generate(file, :skip_page_creation => true) do
|
20
|
+
point = [bounds.right-50, bounds.bottom + 25]
|
21
|
+
page_counter = lazy_bounding_box(point, :width => 50) do
|
22
|
+
text "Page: #{page_count}"
|
23
|
+
end
|
24
|
+
|
25
|
+
10.times do
|
26
|
+
start_new_page
|
27
|
+
text "Some filler text for the page"
|
28
|
+
page_counter.draw
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Padded box is a kind of bounding box which places padding on all sides of
|
4
|
+
# the current bounds. This is easier to see than explain, so please run the
|
5
|
+
# example.
|
6
|
+
#
|
7
|
+
# Feature borrowed from Josh Knowle's pt at:
|
8
|
+
# http://github.com/joshknowles/pt/tree/master
|
9
|
+
#
|
10
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
|
11
|
+
require "rubygems"
|
12
|
+
require "prawn"
|
13
|
+
require "prawn/layout"
|
14
|
+
|
15
|
+
Prawn::Document.generate('padded_box.pdf') do
|
16
|
+
stroke_bounds
|
17
|
+
text "Margin box"
|
18
|
+
padded_box(25) do
|
19
|
+
stroke_bounds
|
20
|
+
text "Bounding box padded by 25 on all sides from the margins"
|
21
|
+
padded_box(50) do
|
22
|
+
stroke_bounds
|
23
|
+
text "Bounding box padded by 50 on all sides from the parent bounds"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/examples/table/cell.rb
CHANGED
@@ -19,8 +19,8 @@ Prawn::Document.generate("cell.pdf") do
|
|
19
19
|
:border_width => 3, :padding => 10,
|
20
20
|
:text => "And that puppies are made of gravy", :document => self, :font_size => 9)
|
21
21
|
cell3 = Prawn::Table::Cell.new(
|
22
|
-
:border_width => 3, :padding => 10, :width => 100,
|
23
|
-
:text => "This is simply the way of the world", :document => self)
|
22
|
+
:border_width => 3, :padding => 10, :width => 100,
|
23
|
+
:text => "This is simply the way of the world", :document => self, :font_style => :bold)
|
24
24
|
|
25
25
|
3.times do
|
26
26
|
cellblock = Prawn::Table::CellBlock.new(self)
|
data/lib/prawn/layout.rb
CHANGED
@@ -0,0 +1,238 @@
|
|
1
|
+
module Prawn
|
2
|
+
class Document
|
3
|
+
# Defines the grid system for a particular document. Takes the number of rows and columns and the
|
4
|
+
# width to use for the gutter as the keys :rows, :columns, :gutter
|
5
|
+
#
|
6
|
+
def define_grid(options = {})
|
7
|
+
@grid = Grid.new(self, options)
|
8
|
+
end
|
9
|
+
|
10
|
+
# A method that can either be used to access a particular grid on the page or interogate the grid
|
11
|
+
# system directly.
|
12
|
+
#
|
13
|
+
# @pdf.grid # Get the Grid directly
|
14
|
+
# @pdf.grid([0,1]) # Get the box at [0,1]
|
15
|
+
# @pdf.grid([0,1], [1,2]) # Get a multi-box spanning from [0,1] to [1,2]
|
16
|
+
def grid(*args)
|
17
|
+
@boxes ||= {}
|
18
|
+
@boxes[args] ||= if args.empty?
|
19
|
+
@grid
|
20
|
+
else
|
21
|
+
g1, g2 = args
|
22
|
+
if(g1.class == Array && g2.class == Array &&
|
23
|
+
g1.length == 2 && g2.length == 2)
|
24
|
+
multi_box(single_box(*g1), single_box(*g2))
|
25
|
+
else
|
26
|
+
single_box(g1, g2)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# A Grid represents the entire grid system of a Page and calculates the column width and row height
|
32
|
+
# of the base box.
|
33
|
+
class Grid
|
34
|
+
attr_reader :pdf, :columns, :rows, :gutter
|
35
|
+
# :nodoc
|
36
|
+
def initialize(pdf, options = {})
|
37
|
+
Prawn.verify_options([:columns, :rows, :gutter], options)
|
38
|
+
|
39
|
+
@pdf = pdf
|
40
|
+
@columns = options[:columns]
|
41
|
+
@rows = options[:rows]
|
42
|
+
@gutter = options[:gutter].to_f
|
43
|
+
end
|
44
|
+
|
45
|
+
# Calculates the base width of boxes.
|
46
|
+
def column_width
|
47
|
+
@column_width ||= subdivide(pdf.bounds.width, columns)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Calculates the base height of boxes.
|
51
|
+
def row_height
|
52
|
+
@row_height ||= subdivide(pdf.bounds.height, rows)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Diagnostic tool to show all of the grids. Defaults to gray.
|
56
|
+
def show_all(color = "CCCCCC")
|
57
|
+
self.rows.times do |i|
|
58
|
+
self.columns.times do |j|
|
59
|
+
pdf.grid(i,j).show(color)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
def subdivide(total, num)
|
66
|
+
(total.to_f - (gutter * (num - 1).to_f)) / num.to_f
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# A Box is a class that represents a bounded area of a page. A Grid object has methods that allow
|
71
|
+
# easy access to the coordinates of its corners, which can be plugged into most existing prawn
|
72
|
+
# methods.
|
73
|
+
#
|
74
|
+
class Box
|
75
|
+
attr_reader :pdf
|
76
|
+
|
77
|
+
def initialize(pdf, i, j)
|
78
|
+
@pdf = pdf
|
79
|
+
@i = i
|
80
|
+
@j = j
|
81
|
+
end
|
82
|
+
|
83
|
+
# Mostly diagnostic method that outputs the name of a box as col_num, row_num
|
84
|
+
def name
|
85
|
+
"#{@i.to_s},#{@j.to_s}"
|
86
|
+
end
|
87
|
+
|
88
|
+
# :nodoc
|
89
|
+
def total_height
|
90
|
+
pdf.bounds.height.to_f
|
91
|
+
end
|
92
|
+
|
93
|
+
# Width of a box
|
94
|
+
def width
|
95
|
+
grid.column_width.to_f
|
96
|
+
end
|
97
|
+
|
98
|
+
# Height of a box
|
99
|
+
def height
|
100
|
+
grid.row_height.to_f
|
101
|
+
end
|
102
|
+
|
103
|
+
# Width of the gutter
|
104
|
+
def gutter
|
105
|
+
grid.gutter.to_f
|
106
|
+
end
|
107
|
+
|
108
|
+
# x-coordinate of left side
|
109
|
+
def left
|
110
|
+
@left ||= (width + gutter) * @j.to_f
|
111
|
+
end
|
112
|
+
|
113
|
+
# x-coordinate of right side
|
114
|
+
def right
|
115
|
+
@right ||= left + width
|
116
|
+
end
|
117
|
+
|
118
|
+
# y-coordinate of the top
|
119
|
+
def top
|
120
|
+
@top ||= total_height - ((height + gutter) * @i.to_f)
|
121
|
+
end
|
122
|
+
|
123
|
+
# y-coordinate of the bottom
|
124
|
+
def bottom
|
125
|
+
@bottom ||= top - height
|
126
|
+
end
|
127
|
+
|
128
|
+
# x,y coordinates of top left corner
|
129
|
+
def top_left
|
130
|
+
[left, top]
|
131
|
+
end
|
132
|
+
|
133
|
+
# x,y coordinates of top right corner
|
134
|
+
def top_right
|
135
|
+
[right, top]
|
136
|
+
end
|
137
|
+
|
138
|
+
# x,y coordinates of bottom left corner
|
139
|
+
def bottom_left
|
140
|
+
[left, bottom]
|
141
|
+
end
|
142
|
+
|
143
|
+
# x,y coordinates of bottom right corner
|
144
|
+
def bottom_right
|
145
|
+
[right, bottom]
|
146
|
+
end
|
147
|
+
|
148
|
+
# Creates a standard bounding box based on the grid box.
|
149
|
+
def bounding_box(&blk)
|
150
|
+
pdf.bounding_box(top_left, :width => width, :height => height, &blk)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Diagnostic method
|
154
|
+
def show(grid_color = "CCCCCC")
|
155
|
+
self.bounding_box do
|
156
|
+
pdf.stroke_color = grid_color
|
157
|
+
pdf.text self.name
|
158
|
+
pdf.stroke_bounds
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
def grid
|
164
|
+
pdf.grid
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# A MultiBox is specified by 2 Boxes and spans the areas between.
|
169
|
+
class MultiBox < Box
|
170
|
+
def initialize(pdf, b1, b2)
|
171
|
+
@pdf = pdf
|
172
|
+
@bs = [b1, b2]
|
173
|
+
end
|
174
|
+
|
175
|
+
def name
|
176
|
+
@bs.map {|b| b.name}.join(":")
|
177
|
+
end
|
178
|
+
|
179
|
+
def total_height
|
180
|
+
@bs[0].total_height
|
181
|
+
end
|
182
|
+
|
183
|
+
def width
|
184
|
+
right_box.right - left_box.left
|
185
|
+
end
|
186
|
+
|
187
|
+
def height
|
188
|
+
top_box.top - bottom_box.bottom
|
189
|
+
end
|
190
|
+
|
191
|
+
def gutter
|
192
|
+
@bs[0].gutter
|
193
|
+
end
|
194
|
+
|
195
|
+
def left
|
196
|
+
left_box.left
|
197
|
+
end
|
198
|
+
|
199
|
+
def right
|
200
|
+
right_box.right
|
201
|
+
end
|
202
|
+
|
203
|
+
def top
|
204
|
+
top_box.top
|
205
|
+
end
|
206
|
+
|
207
|
+
def bottom
|
208
|
+
bottom_box.bottom
|
209
|
+
end
|
210
|
+
|
211
|
+
private
|
212
|
+
def left_box
|
213
|
+
@left_box ||= @bs.min {|a,b| a.left <=> b.left}
|
214
|
+
end
|
215
|
+
|
216
|
+
def right_box
|
217
|
+
@right_box ||= @bs.max {|a,b| a.right <=> b.right}
|
218
|
+
end
|
219
|
+
|
220
|
+
def top_box
|
221
|
+
@top_box ||= @bs.max {|a,b| a.top <=> b.top}
|
222
|
+
end
|
223
|
+
|
224
|
+
def bottom_box
|
225
|
+
@bottom_box ||= @bs.min {|a,b| a.bottom <=> b.bottom}
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
private
|
230
|
+
def single_box(i, j)
|
231
|
+
Box.new(self, i, j)
|
232
|
+
end
|
233
|
+
|
234
|
+
def multi_box(b1, b2)
|
235
|
+
MultiBox.new(self, b1, b2)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# layout/page.rb : Provides helpers for page layout
|
4
|
+
#
|
5
|
+
# Copyright January 2009, 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
|
+
# A LazyBoundingBox is simply a BoundingBox with an action tied to it to be
|
12
|
+
# executed later. The lazy_bounding_box method takes the same arguments as
|
13
|
+
# bounding_box, but returns a LazyBoundingBox object instead of executing
|
14
|
+
# the code block directly.
|
15
|
+
#
|
16
|
+
# You can then call LazyBoundingBox#draw at any time (or multiple times if
|
17
|
+
# you wish), and the contents of the block will then be run. This can be
|
18
|
+
# useful for assembling repeating page elements or reusable components.
|
19
|
+
#
|
20
|
+
# file = "lazy_bounding_boxes.pdf"
|
21
|
+
# Prawn::Document.generate(file, :skip_page_creation => true) do
|
22
|
+
# point = [bounds.right-50, bounds.bottom + 25]
|
23
|
+
# page_counter = lazy_bounding_box(point, :width => 50) do
|
24
|
+
# text "Page: #{page_count}"
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# 10.times do
|
28
|
+
# start_new_page
|
29
|
+
# text "Some text"
|
30
|
+
# page_counter.draw
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
def lazy_bounding_box(*args,&block)
|
35
|
+
translate!(args[0])
|
36
|
+
box = LazyBoundingBox.new(self,*args)
|
37
|
+
box.action(&block)
|
38
|
+
return box
|
39
|
+
end
|
40
|
+
|
41
|
+
# A bounding box with the same dimensions of its parents, minus a margin
|
42
|
+
# on all sides
|
43
|
+
#
|
44
|
+
def padded_box(margin, &block)
|
45
|
+
bounding_box [bounds.left + margin, bounds.top - margin],
|
46
|
+
:width => bounds.width - (margin * 2),
|
47
|
+
:height => bounds.height - (margin * 2), &block
|
48
|
+
end
|
49
|
+
|
50
|
+
# A header is a LazyBoundingBox drawn relative to the margins that can be
|
51
|
+
# repeated on every page of the document.
|
52
|
+
#
|
53
|
+
# Unless <tt>:width</tt> or <tt>:height</tt> are specified, the margin_box
|
54
|
+
# width and height are used.
|
55
|
+
#
|
56
|
+
# header margin_box.top_left do
|
57
|
+
# text "Here's My Fancy Header", :size => 25, :align => :center
|
58
|
+
# stroke_horizontal_rule
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
def header(top_left,options={},&block)
|
62
|
+
@header = repeating_page_element(top_left,options,&block)
|
63
|
+
end
|
64
|
+
|
65
|
+
# A footer is a LazyBoundingBox drawn relative to the margins that can be
|
66
|
+
# repeated on every page of the document.
|
67
|
+
#
|
68
|
+
# Unless <tt>:width</tt> or <tt>:height</tt> are specified, the margin_box
|
69
|
+
# width and height are used.
|
70
|
+
#
|
71
|
+
# footer [margin_box.left, margin_box.bottom + 25] do
|
72
|
+
# stroke_horizontal_rule
|
73
|
+
# text "And here's a sexy footer", :size => 16
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
def footer(top_left,options={},&block)
|
77
|
+
@footer = repeating_page_element(top_left,options,&block)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def repeating_page_element(top_left,options={},&block)
|
83
|
+
r = LazyBoundingBox.new(self, translate(top_left),
|
84
|
+
:width => options[:width] || margin_box.width,
|
85
|
+
:height => options[:height] || margin_box.height )
|
86
|
+
r.action(&block)
|
87
|
+
return r
|
88
|
+
end
|
89
|
+
|
90
|
+
class LazyBoundingBox < BoundingBox
|
91
|
+
|
92
|
+
# Defines the block to be executed by LazyBoundingBox#draw.
|
93
|
+
# Usually, this will be used via a higher level interface.
|
94
|
+
# See the documentation for Document#lazy_bounding_box, Document#header,
|
95
|
+
# and Document#footer
|
96
|
+
#
|
97
|
+
def action(&block)
|
98
|
+
@action = block
|
99
|
+
end
|
100
|
+
|
101
|
+
# Sets Document#bounds to use the LazyBoundingBox for its bounds,
|
102
|
+
# runs the block specified by LazyBoundingBox#action,
|
103
|
+
# and then restores the original bounds of the document.
|
104
|
+
#
|
105
|
+
def draw
|
106
|
+
@parent.mask(:y) do
|
107
|
+
parent_box = @parent.bounds
|
108
|
+
@parent.bounds = self
|
109
|
+
@parent.y = absolute_top
|
110
|
+
@action.call
|
111
|
+
@parent.bounds = parent_box
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/lib/prawn/table.rb
CHANGED
@@ -42,7 +42,7 @@ module Prawn
|
|
42
42
|
# Will raise <tt>Prawn::Errors::EmptyTable</tt> given
|
43
43
|
# a nil or empty <tt>data</tt> paramater.
|
44
44
|
#
|
45
|
-
def table(data,options={})
|
45
|
+
def table(data, options={})
|
46
46
|
if data.nil? || data.empty?
|
47
47
|
raise Prawn::Errors::EmptyTable,
|
48
48
|
"data must be a non-empty, non-nil, two dimensional array of Prawn::Cells or strings"
|
@@ -107,7 +107,6 @@ module Prawn
|
|
107
107
|
# <tt>:column_widths:</tt> A hash of indices and widths in PDF points. E.g. <tt>{ 0 => 50, 1 => 100 }</tt>
|
108
108
|
# <tt>:row_colors</tt>:: An array of row background colors which are used cyclicly.
|
109
109
|
# <tt>:align</tt>:: Alignment of text in columns, for entire table (<tt>:center</tt>) or by column (<tt>{ 0 => :left, 1 => :center}</tt>)
|
110
|
-
# <tt>:minimum_rows</tt>:: The minimum rows to display on a page, including header.
|
111
110
|
#
|
112
111
|
# Row colors are specified as html encoded values, e.g.
|
113
112
|
# ["ffffff","aaaaaa","ccaaff"]. You can also specify
|
@@ -117,7 +116,7 @@ module Prawn
|
|
117
116
|
# See Document#table for typical usage, as directly using this class is
|
118
117
|
# not recommended unless you know why you want to do it.
|
119
118
|
#
|
120
|
-
def initialize(data, document,options={})
|
119
|
+
def initialize(data, document, options={})
|
121
120
|
unless data.all? { |e| Array === e }
|
122
121
|
raise Prawn::Errors::InvalidTableData,
|
123
122
|
"data must be a two dimensional array of Prawn::Cells or strings"
|
@@ -190,15 +189,28 @@ module Prawn
|
|
190
189
|
def calculate_column_widths(manual_widths=nil, width=nil)
|
191
190
|
@column_widths = [0] * @data[0].inject(0){ |acc, e|
|
192
191
|
acc += (e.is_a?(Hash) && e.has_key?(:colspan)) ? e[:colspan] : 1 }
|
192
|
+
|
193
193
|
renderable_data.each do |row|
|
194
|
+
colspan = 0
|
194
195
|
row.each_with_index do |cell,i|
|
195
|
-
|
196
|
-
|
196
|
+
cell_text = cell.is_a?(Hash) ? cell[:text] : cell.to_s
|
197
|
+
length = cell_text.lines.map { |e|
|
198
|
+
@document.width_of(e, :size => C(:font_size)) }.max.to_f +
|
197
199
|
2*C(:horizontal_padding)
|
198
|
-
|
200
|
+
if length > @column_widths[i+colspan]
|
201
|
+
@column_widths[i+colspan] = length.ceil
|
202
|
+
end
|
203
|
+
|
204
|
+
if cell.is_a?(Hash) && cell[:colspan]
|
205
|
+
colspan += cell[:colspan] - 1
|
206
|
+
end
|
199
207
|
end
|
200
208
|
end
|
201
209
|
|
210
|
+
fit_within_bounds(manual_widths, width)
|
211
|
+
end
|
212
|
+
|
213
|
+
def fit_within_bounds(manual_widths, width)
|
202
214
|
manual_width = 0
|
203
215
|
manual_widths.each { |k,v|
|
204
216
|
@column_widths[k] = v; manual_width += v } if manual_widths
|
@@ -227,6 +239,7 @@ module Prawn
|
|
227
239
|
end
|
228
240
|
end
|
229
241
|
|
242
|
+
|
230
243
|
def renderable_data
|
231
244
|
C(:headers) ? [C(:headers)] + @data : @data
|
232
245
|
end
|
@@ -270,15 +283,18 @@ module Prawn
|
|
270
283
|
@column_widths[col_index]
|
271
284
|
end
|
272
285
|
|
273
|
-
|
274
|
-
:document => @document,
|
286
|
+
cell_options = {:document => @document,
|
275
287
|
:text => text,
|
276
288
|
:width => width,
|
277
289
|
:horizontal_padding => C(:horizontal_padding),
|
278
290
|
:vertical_padding => C(:vertical_padding),
|
279
291
|
:border_width => C(:border_width),
|
280
292
|
:border_style => :sides,
|
281
|
-
:align => align
|
293
|
+
:align => align}
|
294
|
+
cell_options[:font_style] = e[:font_style] if e.is_a?(Hash) && e.has_key?(:font_style)
|
295
|
+
cell_options[:font_size] = e[:font_size] if e.is_a?(Hash) && e.has_key?(:font_size)
|
296
|
+
|
297
|
+
c << Prawn::Table::Cell.new(cell_options)
|
282
298
|
end
|
283
299
|
|
284
300
|
col_index += (e.is_a?(Hash) && e.has_key?(:colspan)) ? e[:colspan] : 1
|
data/lib/prawn/table/cell.rb
CHANGED
@@ -52,6 +52,7 @@ module Prawn
|
|
52
52
|
# <tt>:border_style</tt>:: One of <tt>:all</tt>, <tt>:no_top</tt>, <tt>:no_bottom</tt>, <tt>:sides</tt>, <tt>:none</tt>, <tt>:bottom_only</tt>. Defaults to :all.
|
53
53
|
# <tt>:border_color</tt>:: The color of the cell border.
|
54
54
|
# <tt>:font_size</tt>:: The font size for the cell text.
|
55
|
+
# <tt>:font_style</tt>:: The font style for the cell text.
|
55
56
|
#
|
56
57
|
def initialize(options={})
|
57
58
|
@point = options[:point]
|
@@ -67,6 +68,7 @@ module Prawn
|
|
67
68
|
@background_color = options[:background_color]
|
68
69
|
@align = options[:align] || :left
|
69
70
|
@font_size = options[:font_size]
|
71
|
+
@font_style = options[:font_style]
|
70
72
|
|
71
73
|
@horizontal_padding = options[:horizontal_padding] || 0
|
72
74
|
@vertical_padding = options[:vertical_padding] || 0
|
@@ -78,7 +80,7 @@ module Prawn
|
|
78
80
|
|
79
81
|
attr_accessor :point, :border_style, :border_width, :background_color,
|
80
82
|
:document, :horizontal_padding, :vertical_padding, :align,
|
81
|
-
:borders, :text_color, :border_color
|
83
|
+
:borders, :text_color, :border_color, :font_size, :font_style
|
82
84
|
|
83
85
|
attr_writer :height, :width #:nodoc:
|
84
86
|
|
@@ -97,7 +99,7 @@ module Prawn
|
|
97
99
|
# The width of the cell in PDF points
|
98
100
|
#
|
99
101
|
def width
|
100
|
-
@width || (@document.
|
102
|
+
@width || (@document.width_of(@text, :size => @font_size)) + 2*@horizontal_padding
|
101
103
|
end
|
102
104
|
|
103
105
|
# The height of the cell in PDF points
|
@@ -109,7 +111,15 @@ module Prawn
|
|
109
111
|
# The height of the text area excluding the vertical padding
|
110
112
|
#
|
111
113
|
def text_area_height
|
112
|
-
|
114
|
+
text_height = 0
|
115
|
+
if @font_size
|
116
|
+
@document.font_size(@font_size) do
|
117
|
+
text_height = @document.height_of(@text, text_area_width)
|
118
|
+
end
|
119
|
+
else
|
120
|
+
text_height = @document.height_of(@text, text_area_width)
|
121
|
+
end
|
122
|
+
text_height
|
113
123
|
end
|
114
124
|
|
115
125
|
# Draws the cell onto the PDF document
|
@@ -173,6 +183,7 @@ module Prawn
|
|
173
183
|
options = {:align => @align, :final_gap => false}
|
174
184
|
|
175
185
|
options[:size] = @font_size if @font_size
|
186
|
+
options[:style] = @font_style if @font_style
|
176
187
|
|
177
188
|
@document.mask(:fill_color) do
|
178
189
|
@document.fill_color @text_color if @text_color
|
data/spec/grid_spec.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
3
|
+
|
4
|
+
describe "A document's grid" do
|
5
|
+
before do
|
6
|
+
@pdf = Prawn::Document.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should allow definition of a grid" do
|
10
|
+
@pdf.define_grid(:columns => 5, :rows => 8, :gutter => 0.1)
|
11
|
+
@pdf.grid.columns.should == 5
|
12
|
+
@pdf.grid.rows.should == 8
|
13
|
+
@pdf.grid.gutter.should == 0.1
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "when a grid is defined" do
|
17
|
+
before do
|
18
|
+
@num_columns = 5
|
19
|
+
@num_rows = 8
|
20
|
+
@gutter = 10.0
|
21
|
+
@pdf.define_grid(
|
22
|
+
:columns => @num_columns,
|
23
|
+
:rows => @num_rows,
|
24
|
+
:gutter => @gutter
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should compute the column width" do
|
29
|
+
(@pdf.grid.column_width * @num_columns.to_f +
|
30
|
+
@gutter * (@num_columns - 1).to_f).should == @pdf.bounds.width
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should compute the row height" do
|
34
|
+
(@pdf.grid.row_height * @num_rows.to_f +
|
35
|
+
@gutter * (@num_rows - 1).to_f).should == @pdf.bounds.height
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should give the edges of a grid box" do
|
39
|
+
grid_width = (@pdf.bounds.width.to_f -
|
40
|
+
(@gutter * (@num_columns - 1).to_f )) / @num_columns.to_f
|
41
|
+
grid_height = (@pdf.bounds.height.to_f -
|
42
|
+
(@gutter * (@num_rows - 1).to_f ))/ @num_rows.to_f
|
43
|
+
|
44
|
+
exp_tl_x = (grid_width + @gutter.to_f) * 4.0
|
45
|
+
exp_tl_y = @pdf.bounds.height.to_f - (grid_height + @gutter.to_f)
|
46
|
+
|
47
|
+
@pdf.grid(1,4).top_left.should == [exp_tl_x, exp_tl_y]
|
48
|
+
@pdf.grid(1,4).top_right.should == [exp_tl_x + grid_width, exp_tl_y]
|
49
|
+
@pdf.grid(1,4).bottom_left.should == [exp_tl_x, exp_tl_y - grid_height]
|
50
|
+
@pdf.grid(1,4).bottom_right.should == [exp_tl_x + grid_width, exp_tl_y - grid_height]
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should give the edges of a multiple grid boxes" do
|
54
|
+
# Hand verified. Cheating a bit. Don't tell.
|
55
|
+
@pdf.grid([1,3], [2,5]).top_left.should == [330.0, 628.75]
|
56
|
+
@pdf.grid([1,3], [2,5]).top_right.should == [650.0, 628.75]
|
57
|
+
@pdf.grid([1,3], [2,5]).bottom_left.should == [330.0, 456.25]
|
58
|
+
@pdf.grid([1,3], [2,5]).bottom_right.should == [650.0, 456.25]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
3
|
+
|
4
|
+
describe "When beginning each new page" do
|
5
|
+
|
6
|
+
it "should execute codeblock given to Document#header" do
|
7
|
+
call_count = 0
|
8
|
+
|
9
|
+
pdf = Prawn::Document.new
|
10
|
+
pdf.header(pdf.margin_box.top_left) do
|
11
|
+
call_count += 1
|
12
|
+
end
|
13
|
+
|
14
|
+
pdf.start_new_page
|
15
|
+
pdf.start_new_page
|
16
|
+
pdf.render
|
17
|
+
|
18
|
+
call_count.should == 3
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "When ending each page" do
|
24
|
+
|
25
|
+
it "should execute codeblock given to Document#footer" do
|
26
|
+
|
27
|
+
call_count = 0
|
28
|
+
|
29
|
+
pdf = Prawn::Document.new
|
30
|
+
pdf.footer([pdf.margin_box.left, pdf.margin_box.bottom + 50]) do
|
31
|
+
call_count += 1
|
32
|
+
end
|
33
|
+
|
34
|
+
pdf.start_new_page
|
35
|
+
pdf.start_new_page
|
36
|
+
pdf.render
|
37
|
+
|
38
|
+
call_count.should == 3
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -5,7 +5,7 @@ puts "Prawn specs: Running on Ruby Version: #{RUBY_VERSION}"
|
|
5
5
|
require "rubygems"
|
6
6
|
require "test/spec"
|
7
7
|
require "mocha"
|
8
|
-
$LOAD_PATH
|
8
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
9
9
|
|
10
10
|
require "prawn"
|
11
11
|
require "prawn/layout"
|
data/spec/table_spec.rb
CHANGED
@@ -10,6 +10,25 @@ describe "A table's width" do
|
|
10
10
|
|
11
11
|
table.width.should == 300
|
12
12
|
end
|
13
|
+
it "should calculate unspecified column widths even " +
|
14
|
+
"with colspan cells declared" do
|
15
|
+
pdf = Prawn::Document.new
|
16
|
+
hpad, fs = 3, 5
|
17
|
+
columns = 3
|
18
|
+
|
19
|
+
data = [ [ { :text => 'foo', :colspan => 2 }, "foobar" ],
|
20
|
+
[ "foo", "foo", "foo" ] ]
|
21
|
+
table = Prawn::Table.new( data, pdf,
|
22
|
+
:horizontal_padding => hpad,
|
23
|
+
:font_size => fs )
|
24
|
+
|
25
|
+
col0_width = pdf.width_of("foo", :size => fs) # cell 1, 0
|
26
|
+
col1_width = pdf.width_of("foo", :size => fs) # cell 1, 1
|
27
|
+
col2_width = pdf.width_of("foobar", :size => fs) # cell 0, 1 (at col 2)
|
28
|
+
|
29
|
+
table.width.should == col0_width.ceil + col1_width.ceil +
|
30
|
+
col2_width.ceil + 2*columns*hpad
|
31
|
+
end
|
13
32
|
|
14
33
|
it "should calculate unspecified column widths as "+
|
15
34
|
"(max(string_width).ceil + 2*horizontal_padding)" do
|
@@ -19,8 +38,8 @@ describe "A table's width" do
|
|
19
38
|
table = Prawn::Table.new( [%w[ foo b ], %w[d foobar]], pdf,
|
20
39
|
:horizontal_padding => hpad, :font_size => fs)
|
21
40
|
|
22
|
-
col0_width = pdf.
|
23
|
-
col1_width = pdf.
|
41
|
+
col0_width = pdf.width_of("foo", :size => fs)
|
42
|
+
col1_width = pdf.width_of("foobar", :size => fs)
|
24
43
|
|
25
44
|
table.width.should == col0_width.ceil + col1_width.ceil + 2*columns*hpad
|
26
45
|
end
|
@@ -33,8 +52,8 @@ describe "A table's width" do
|
|
33
52
|
stretchy_columns = 2
|
34
53
|
|
35
54
|
col0_width = 50
|
36
|
-
col1_width = pdf.
|
37
|
-
col2_width = pdf.
|
55
|
+
col1_width = pdf.width_of("foo", :size => fs)
|
56
|
+
col2_width = pdf.width_of("foobar", :size => fs)
|
38
57
|
col3_width = 150
|
39
58
|
|
40
59
|
table = Prawn::Table.new( [%w[snake foo b apple],
|
@@ -54,7 +73,9 @@ describe "A table's width" do
|
|
54
73
|
expected_width = pdf.margin_box.width
|
55
74
|
|
56
75
|
data = [
|
57
|
-
['This is a column with a lot of text that should comfortably exceed
|
76
|
+
['This is a column with a lot of text that should comfortably exceed '+
|
77
|
+
'the width of a normal document margin_box width', 'Some more text',
|
78
|
+
'and then some more', 'Just a bit more to be extra sure']
|
58
79
|
]
|
59
80
|
|
60
81
|
table = Prawn::Table.new(data, pdf)
|
@@ -69,9 +90,12 @@ describe "A table's width" do
|
|
69
90
|
expected_width = pdf.margin_box.width
|
70
91
|
|
71
92
|
data = [
|
72
|
-
['This is a column with a lot of text that should comfortably exceed
|
93
|
+
['This is a column with a lot of text that should comfortably exceed '+
|
94
|
+
'the width of a normal document margin_box width', 'Some more text',
|
95
|
+
'and then some more', 'Just a bit more to be extra sure']
|
73
96
|
]
|
74
97
|
|
98
|
+
|
75
99
|
table = Prawn::Table.new(data, pdf, :column_widths => { 1 => 100 })
|
76
100
|
|
77
101
|
table.width.should == expected_width
|
@@ -98,7 +122,9 @@ describe "A table's width" do
|
|
98
122
|
expected_width = 400
|
99
123
|
|
100
124
|
data = [
|
101
|
-
['This is a column with a lot of text that should comfortably exceed
|
125
|
+
['This is a column with a lot of text that should comfortably exceed '+
|
126
|
+
'the width of a normal document margin_box width', 'Some more text',
|
127
|
+
'and then some more', 'Just a bit more to be extra sure']
|
102
128
|
]
|
103
129
|
|
104
130
|
table = Prawn::Table.new(data, pdf, :width => expected_width)
|
@@ -113,7 +139,9 @@ describe "A table's width" do
|
|
113
139
|
expected_width = 400
|
114
140
|
|
115
141
|
data = [
|
116
|
-
['This is a column with a lot of text that should comfortably exceed
|
142
|
+
['This is a column with a lot of text that should comfortably exceed '+
|
143
|
+
'the width of a normal document margin_box width', 'Some more text',
|
144
|
+
'and then some more', 'Just a bit more to be extra sure']
|
117
145
|
]
|
118
146
|
|
119
147
|
table = Prawn::Table.new(data, pdf, :column_widths => { 1 => 100 }, :width => expected_width)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prawn-layout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gregory Brown
|
@@ -9,11 +9,11 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-06-15 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
|
-
description: An extension to Prawn that provides table support and other layout functionality
|
16
|
+
description: " An extension to Prawn that provides table support and other layout functionality\n"
|
17
17
|
email: " gregory.t.brown@gmail.com"
|
18
18
|
executables: []
|
19
19
|
|
@@ -22,7 +22,10 @@ extensions: []
|
|
22
22
|
extra_rdoc_files: []
|
23
23
|
|
24
24
|
files:
|
25
|
-
- examples/
|
25
|
+
- examples/grid/simple_grid.rb
|
26
|
+
- examples/page_layout/flowing_text_with_header_and_footer.rb
|
27
|
+
- examples/page_layout/lazy_bounding_boxes.rb
|
28
|
+
- examples/page_layout/padded_box.rb
|
26
29
|
- examples/table/addressbook.csv
|
27
30
|
- examples/table/cell.rb
|
28
31
|
- examples/table/currency.csv
|
@@ -34,16 +37,20 @@ files:
|
|
34
37
|
- examples/table/table_header_color.rb
|
35
38
|
- examples/table/table_header_underline.rb
|
36
39
|
- examples/table/table_widths.rb
|
37
|
-
- lib/prawn
|
40
|
+
- lib/prawn/layout/grid.rb
|
41
|
+
- lib/prawn/layout/page.rb
|
38
42
|
- lib/prawn/layout.rb
|
39
|
-
- lib/prawn/table
|
40
43
|
- lib/prawn/table/cell.rb
|
41
44
|
- lib/prawn/table.rb
|
45
|
+
- spec/grid_spec.rb
|
46
|
+
- spec/page_layout_spec.rb
|
42
47
|
- spec/spec_helper.rb
|
43
48
|
- spec/table_spec.rb
|
44
49
|
- Rakefile
|
45
50
|
has_rdoc: true
|
46
51
|
homepage: http://prawn.majesticseacreature.com
|
52
|
+
licenses: []
|
53
|
+
|
47
54
|
post_install_message:
|
48
55
|
rdoc_options:
|
49
56
|
- --title
|
@@ -65,9 +72,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
65
72
|
requirements: []
|
66
73
|
|
67
74
|
rubyforge_project: prawn
|
68
|
-
rubygems_version: 1.3.
|
75
|
+
rubygems_version: 1.3.4
|
69
76
|
signing_key:
|
70
|
-
specification_version:
|
77
|
+
specification_version: 3
|
71
78
|
summary: An extension to Prawn that provides table support and other layout functionality
|
72
79
|
test_files: []
|
73
80
|
|