prawn 1.1.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -0
  3. data/lib/prawn.rb +2 -2
  4. data/lib/prawn/text/box.rb +2 -0
  5. data/lib/prawn/text/formatted/box.rb +46 -21
  6. data/lib/prawn/text/formatted/line_wrap.rb +8 -2
  7. data/lib/prawn/text/formatted/wrap.rb +3 -1
  8. data/manual/contents.rb +1 -1
  9. data/manual/example_helper.rb +0 -1
  10. data/manual/table.rb +16 -0
  11. data/manual/text/text_box_overflow.rb +4 -0
  12. data/prawn.gemspec +2 -3
  13. data/spec/formatted_text_box_spec.rb +22 -0
  14. data/spec/line_wrap_spec.rb +4 -0
  15. data/spec/text_box_spec.rb +28 -0
  16. data/spec/text_spec.rb +19 -0
  17. metadata +6 -50
  18. data/lib/prawn/table.rb +0 -644
  19. data/lib/prawn/table/cell.rb +0 -772
  20. data/lib/prawn/table/cell/image.rb +0 -69
  21. data/lib/prawn/table/cell/in_table.rb +0 -33
  22. data/lib/prawn/table/cell/span_dummy.rb +0 -93
  23. data/lib/prawn/table/cell/subtable.rb +0 -66
  24. data/lib/prawn/table/cell/text.rb +0 -154
  25. data/lib/prawn/table/cells.rb +0 -255
  26. data/lib/prawn/table/column_width_calculator.rb +0 -182
  27. data/manual/table/basic_block.rb +0 -53
  28. data/manual/table/before_rendering_page.rb +0 -26
  29. data/manual/table/cell_border_lines.rb +0 -24
  30. data/manual/table/cell_borders_and_bg.rb +0 -31
  31. data/manual/table/cell_dimensions.rb +0 -30
  32. data/manual/table/cell_text.rb +0 -38
  33. data/manual/table/column_widths.rb +0 -30
  34. data/manual/table/content_and_subtables.rb +0 -39
  35. data/manual/table/creation.rb +0 -27
  36. data/manual/table/filtering.rb +0 -36
  37. data/manual/table/flow_and_header.rb +0 -17
  38. data/manual/table/image_cells.rb +0 -33
  39. data/manual/table/position.rb +0 -29
  40. data/manual/table/row_colors.rb +0 -20
  41. data/manual/table/span.rb +0 -30
  42. data/manual/table/style.rb +0 -22
  43. data/manual/table/table.rb +0 -52
  44. data/manual/table/width.rb +0 -27
  45. data/spec/cell_spec.rb +0 -629
  46. data/spec/table/span_dummy_spec.rb +0 -17
  47. data/spec/table_spec.rb +0 -1527
@@ -1,772 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # cell.rb: Table cell drawing.
4
- #
5
- # Copyright December 2009, Gregory Brown and Brad Ediger. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
-
9
- require 'date'
10
- module Prawn
11
- class Document
12
-
13
- # @group Experimental API
14
-
15
- # Instantiates and draws a cell on the document.
16
- #
17
- # cell(:content => "Hello world!", :at => [12, 34])
18
- #
19
- # See Prawn::Table::Cell.make for full options.
20
- #
21
- def cell(options={})
22
- cell = Table::Cell.make(self, options.delete(:content), options)
23
- cell.draw
24
- cell
25
- end
26
-
27
- # Set up, but do not draw, a cell. Useful for creating cells with
28
- # formatting options to be inserted into a Table. Call +draw+ on the
29
- # resulting Cell to ink it.
30
- #
31
- # See the documentation on Prawn::Cell for details on the arguments.
32
- #
33
- def make_cell(content, options={})
34
- Prawn::Table::Cell.make(self, content, options)
35
- end
36
-
37
- end
38
-
39
- class Table
40
-
41
- # A Cell is a rectangular area of the page into which content is drawn. It
42
- # has a framework for sizing itself and adding padding and simple styling.
43
- # There are several standard Cell subclasses that handle things like text,
44
- # Tables, and (in the future) stamps, images, and arbitrary content.
45
- #
46
- # Cells are a basic building block for table support (see Prawn::Table).
47
- #
48
- # Please subclass me if you want new content types! I'm designed to be very
49
- # extensible. See the different standard Cell subclasses in
50
- # lib/prawn/table/cell/*.rb for a template.
51
- #
52
- class Cell
53
-
54
- # Amount of dead space (in PDF points) inside the borders but outside the
55
- # content. Padding defaults to 5pt.
56
- #
57
- attr_reader :padding
58
-
59
- # If provided, the minimum width that this cell in its column will permit.
60
- #
61
- def min_width_ignoring_span
62
- set_width_constraints
63
- @min_width
64
- end
65
-
66
- # Minimum width of the entire span group this cell controls.
67
- #
68
- def min_width
69
- return min_width_ignoring_span if @colspan == 1
70
-
71
- # Sum up the largest min-width from each column, including myself.
72
- min_widths = Hash.new(0)
73
- dummy_cells.each do |cell|
74
- min_widths[cell.column] =
75
- [min_widths[cell.column], cell.min_width].max
76
- end
77
- min_widths[column] = [min_widths[column], min_width_ignoring_span].max
78
- min_widths.values.inject(0, &:+)
79
- end
80
-
81
- # Min-width of the span divided by the number of columns.
82
- #
83
- def avg_spanned_min_width
84
- min_width.to_f / colspan
85
- end
86
-
87
- # If provided, the maximum width that this cell can be drawn in, within
88
- # its column.
89
- #
90
- def max_width_ignoring_span
91
- set_width_constraints
92
- @max_width
93
- end
94
-
95
- # Maximum width of the entire span group this cell controls.
96
- #
97
- def max_width
98
- return max_width_ignoring_span if @colspan == 1
99
-
100
- # Sum the smallest max-width from each column in the group, including
101
- # myself.
102
- max_widths = Hash.new(0)
103
- dummy_cells.each do |cell|
104
- max_widths[cell.column] =
105
- [max_widths[cell.column], cell.max_width].min
106
- end
107
- max_widths[column] = [max_widths[column], max_width_ignoring_span].min
108
- max_widths.values.inject(0, &:+)
109
- end
110
-
111
- # Manually specify the cell's height.
112
- #
113
- attr_writer :height
114
-
115
- # Specifies which borders to enable. Must be an array of zero or more of:
116
- # <tt>[:left, :right, :top, :bottom]</tt>.
117
- #
118
- attr_accessor :borders
119
-
120
- # Width, in PDF points, of the cell's borders: [top, right, bottom, left].
121
- #
122
- attr_reader :border_widths
123
-
124
- # HTML RGB-format ("ccffff") border colors: [top, right, bottom, left].
125
- #
126
- attr_reader :border_colors
127
-
128
- # Line style
129
- #
130
- attr_reader :border_lines
131
-
132
- # Specifies the content for the cell. Must be a "cellable" object. See the
133
- # "Data" section of the Prawn::Table documentation for details on cellable
134
- # objects.
135
- #
136
- attr_accessor :content
137
-
138
- # The background color, if any, for this cell. Specified in HTML RGB
139
- # format, e.g., "ccffff". The background is drawn under the whole cell,
140
- # including any padding.
141
- #
142
- attr_accessor :background_color
143
-
144
- # Number of columns this cell spans. Defaults to 1.
145
- #
146
- attr_reader :colspan
147
-
148
- # Number of rows this cell spans. Defaults to 1.
149
- #
150
- attr_reader :rowspan
151
-
152
- # Array of SpanDummy cells (if any) that represent the other cells in
153
- # this span group. They know their own width / height, but do not draw
154
- # anything.
155
- #
156
- attr_reader :dummy_cells
157
-
158
- # Instantiates a Cell based on the given options. The particular class of
159
- # cell returned depends on the :content argument. See the Prawn::Table
160
- # documentation under "Data" for allowable content types.
161
- #
162
- def self.make(pdf, content, options={})
163
- at = options.delete(:at) || [0, pdf.cursor]
164
- content = content.to_s if content.nil? || content.kind_of?(Numeric) ||
165
- content.kind_of?(Date)
166
-
167
- if content.is_a?(Hash)
168
- if content[:image]
169
- return Cell::Image.new(pdf, at, content)
170
- end
171
- options.update(content)
172
- content = options[:content]
173
- else
174
- options[:content] = content
175
- end
176
-
177
- options[:content] = content = "" if content.nil?
178
-
179
- case content
180
- when Prawn::Table::Cell
181
- content
182
- when String
183
- Cell::Text.new(pdf, at, options)
184
- when Prawn::Table
185
- Cell::Subtable.new(pdf, at, options)
186
- when Array
187
- subtable = Prawn::Table.new(options[:content], pdf, {})
188
- Cell::Subtable.new(pdf, at, options.merge(:content => subtable))
189
- else
190
- raise Errors::UnrecognizedTableContent
191
- end
192
- end
193
-
194
- # A small amount added to the bounding box width to cover over floating-
195
- # point errors when round-tripping from content_width to width and back.
196
- # This does not change cell positioning; it only slightly expands each
197
- # cell's bounding box width so that rounding error does not prevent a cell
198
- # from rendering.
199
- #
200
- FPTolerance = 1
201
-
202
- # Sets up a cell on the document +pdf+, at the given x/y location +point+,
203
- # with the given +options+. Cell, like Table, follows the "options set
204
- # accessors" paradigm (see "Options" under the Table documentation), so
205
- # any cell accessor <tt>cell.foo = :bar</tt> can be set by providing the
206
- # option <tt>:foo => :bar</tt> here.
207
- #
208
- def initialize(pdf, point, options={})
209
- @pdf = pdf
210
- @point = point
211
-
212
- # Set defaults; these can be changed by options
213
- @padding = [5, 5, 5, 5]
214
- @borders = [:top, :bottom, :left, :right]
215
- @border_widths = [1] * 4
216
- @border_colors = ['000000'] * 4
217
- @border_lines = [:solid] * 4
218
- @colspan = 1
219
- @rowspan = 1
220
- @dummy_cells = []
221
-
222
- options.each { |k, v| send("#{k}=", v) }
223
-
224
- @initializer_run = true
225
- end
226
-
227
- # Supports setting multiple properties at once.
228
- #
229
- # cell.style(:padding => 0, :border_width => 2)
230
- #
231
- # is the same as:
232
- #
233
- # cell.padding = 0
234
- # cell.border_width = 2
235
- #
236
- def style(options={}, &block)
237
- options.each do |k, v|
238
- send("#{k}=", v) if respond_to?("#{k}=")
239
- end
240
-
241
- # The block form supports running a single block for multiple cells, as
242
- # in Cells#style.
243
- block.call(self) if block
244
- end
245
-
246
- # Returns the width of the cell in its first column alone, ignoring any
247
- # colspans.
248
- #
249
- def width_ignoring_span
250
- # We can't ||= here because the FP error accumulates on the round-trip
251
- # from #content_width.
252
- defined?(@width) && @width || (content_width + padding_left + padding_right)
253
- end
254
-
255
- # Returns the cell's width in points, inclusive of padding. If the cell is
256
- # the master cell of a colspan, returns the width of the entire span
257
- # group.
258
- #
259
- def width
260
- return width_ignoring_span if @colspan == 1 && @rowspan == 1
261
-
262
- # We're in a span group; get the maximum width per column (including
263
- # the master cell) and sum each column.
264
- column_widths = Hash.new(0)
265
- dummy_cells.each do |cell|
266
- column_widths[cell.column] =
267
- [column_widths[cell.column], cell.width].max
268
- end
269
- column_widths[column] = [column_widths[column], width_ignoring_span].max
270
- column_widths.values.inject(0, &:+)
271
- end
272
-
273
- # Manually sets the cell's width, inclusive of padding.
274
- #
275
- def width=(w)
276
- @width = @min_width = @max_width = w
277
- end
278
-
279
- # Returns the width of the bare content in the cell, excluding padding.
280
- #
281
- def content_width
282
- if defined?(@width) && @width # manually set
283
- return @width - padding_left - padding_right
284
- end
285
-
286
- natural_content_width
287
- end
288
-
289
- # Width of the entire span group.
290
- #
291
- def spanned_content_width
292
- width - padding_left - padding_right
293
- end
294
-
295
- # Returns the width this cell would naturally take on, absent other
296
- # constraints. Must be implemented in subclasses.
297
- #
298
- def natural_content_width
299
- raise NotImplementedError,
300
- "subclasses must implement natural_content_width"
301
- end
302
-
303
- # Returns the cell's height in points, inclusive of padding, in its first
304
- # row only.
305
- #
306
- def height_ignoring_span
307
- # We can't ||= here because the FP error accumulates on the round-trip
308
- # from #content_height.
309
- defined?(@height) && @height || (content_height + padding_top + padding_bottom)
310
- end
311
-
312
- # Returns the cell's height in points, inclusive of padding. If the cell
313
- # is the master cell of a rowspan, returns the width of the entire span
314
- # group.
315
- #
316
- def height
317
- return height_ignoring_span if @colspan == 1 && @rowspan == 1
318
-
319
- # We're in a span group; get the maximum height per row (including the
320
- # master cell) and sum each row.
321
- row_heights = Hash.new(0)
322
- dummy_cells.each do |cell|
323
- row_heights[cell.row] = [row_heights[cell.row], cell.height].max
324
- end
325
- row_heights[row] = [row_heights[row], height_ignoring_span].max
326
- row_heights.values.inject(0, &:+)
327
- end
328
-
329
- # Returns the height of the bare content in the cell, excluding padding.
330
- #
331
- def content_height
332
- if defined?(@height) && @height # manually set
333
- return @height - padding_top - padding_bottom
334
- end
335
-
336
- natural_content_height
337
- end
338
-
339
- # Height of the entire span group.
340
- #
341
- def spanned_content_height
342
- height - padding_top - padding_bottom
343
- end
344
-
345
- # Returns the height this cell would naturally take on, absent
346
- # constraints. Must be implemented in subclasses.
347
- #
348
- def natural_content_height
349
- raise NotImplementedError,
350
- "subclasses must implement natural_content_height"
351
- end
352
-
353
- # Indicates the number of columns that this cell is to span. Defaults to
354
- # 1.
355
- #
356
- # This must be provided as part of the table data, like so:
357
- #
358
- # pdf.table([["foo", {:content => "bar", :colspan => 2}]])
359
- #
360
- # Setting colspan from the initializer block is invalid because layout
361
- # has already run. For example, this will NOT work:
362
- #
363
- # pdf.table([["foo", "bar"]]) { cells[0, 1].colspan = 2 }
364
- #
365
- def colspan=(span)
366
- if defined?(@initializer_run) && @initializer_run
367
- raise Prawn::Errors::InvalidTableSpan,
368
- "colspan must be provided in the table's structure, never in the " +
369
- "initialization block. See Prawn's documentation for details."
370
- end
371
-
372
- @colspan = span
373
- end
374
-
375
- # Indicates the number of rows that this cell is to span. Defaults to 1.
376
- #
377
- # This must be provided as part of the table data, like so:
378
- #
379
- # pdf.table([["foo", {:content => "bar", :rowspan => 2}], ["baz"]])
380
- #
381
- # Setting rowspan from the initializer block is invalid because layout
382
- # has already run. For example, this will NOT work:
383
- #
384
- # pdf.table([["foo", "bar"], ["baz"]]) { cells[0, 1].rowspan = 2 }
385
- #
386
- def rowspan=(span)
387
- if defined?(@initializer_run) && @initializer_run
388
- raise Prawn::Errors::InvalidTableSpan,
389
- "rowspan must be provided in the table's structure, never in the " +
390
- "initialization block. See Prawn's documentation for details."
391
- end
392
-
393
- @rowspan = span
394
- end
395
-
396
- # Draws the cell onto the document. Pass in a point [x,y] to override the
397
- # location at which the cell is drawn.
398
- #
399
- # If drawing a group of cells at known positions, look into
400
- # Cell.draw_cells, which ensures that the backgrounds, borders, and
401
- # content are all drawn in correct order so as not to overlap.
402
- #
403
- def draw(pt=[x, y])
404
- Prawn::Table::Cell.draw_cells([[self, pt]])
405
- end
406
-
407
- # Given an array of pairs [cell, pt], draws each cell at its
408
- # corresponding pt, making sure all backgrounds are behind all borders
409
- # and content.
410
- #
411
- def self.draw_cells(cells)
412
- cells.each do |cell, pt|
413
- cell.set_width_constraints
414
- cell.draw_background(pt)
415
- end
416
-
417
- cells.each do |cell, pt|
418
- cell.draw_borders(pt)
419
- cell.draw_bounded_content(pt)
420
- end
421
- end
422
-
423
- # Draws the cell's content at the point provided.
424
- #
425
- def draw_bounded_content(pt)
426
- @pdf.float do
427
- @pdf.bounding_box([pt[0] + padding_left, pt[1] - padding_top],
428
- :width => spanned_content_width + FPTolerance,
429
- :height => spanned_content_height + FPTolerance) do
430
- draw_content
431
- end
432
- end
433
- end
434
-
435
- # x-position of the cell within the parent bounds.
436
- #
437
- def x
438
- @point[0]
439
- end
440
-
441
- # Set the x-position of the cell within the parent bounds.
442
- #
443
- def x=(val)
444
- @point[0] = val
445
- end
446
-
447
- # y-position of the cell within the parent bounds.
448
- #
449
- def y
450
- @point[1]
451
- end
452
-
453
- # Set the y-position of the cell within the parent bounds.
454
- #
455
- def y=(val)
456
- @point[1] = val
457
- end
458
-
459
- # Sets padding on this cell. The argument can be one of:
460
- #
461
- # * an integer (sets all padding)
462
- # * a two-element array [vertical, horizontal]
463
- # * a three-element array [top, horizontal, bottom]
464
- # * a four-element array [top, right, bottom, left]
465
- #
466
- def padding=(pad)
467
- @padding = case
468
- when pad.nil?
469
- [0, 0, 0, 0]
470
- when Numeric === pad # all padding
471
- [pad, pad, pad, pad]
472
- when pad.length == 2 # vert, horiz
473
- [pad[0], pad[1], pad[0], pad[1]]
474
- when pad.length == 3 # top, horiz, bottom
475
- [pad[0], pad[1], pad[2], pad[1]]
476
- when pad.length == 4 # top, right, bottom, left
477
- [pad[0], pad[1], pad[2], pad[3]]
478
- else
479
- raise ArgumentError, ":padding must be a number or an array [v,h] " +
480
- "or [t,r,b,l]"
481
- end
482
- end
483
-
484
- def padding_top
485
- @padding[0]
486
- end
487
-
488
- def padding_top=(val)
489
- @padding[0] = val
490
- end
491
-
492
- def padding_right
493
- @padding[1]
494
- end
495
-
496
- def padding_right=(val)
497
- @padding[1] = val
498
- end
499
-
500
- def padding_bottom
501
- @padding[2]
502
- end
503
-
504
- def padding_bottom=(val)
505
- @padding[2] = val
506
- end
507
-
508
- def padding_left
509
- @padding[3]
510
- end
511
-
512
- def padding_left=(val)
513
- @padding[3] = val
514
- end
515
-
516
- # Sets border colors on this cell. The argument can be one of:
517
- #
518
- # * an integer (sets all colors)
519
- # * a two-element array [vertical, horizontal]
520
- # * a three-element array [top, horizontal, bottom]
521
- # * a four-element array [top, right, bottom, left]
522
- #
523
- def border_color=(color)
524
- @border_colors = case
525
- when color.nil?
526
- ["000000"] * 4
527
- when String === color # all colors
528
- [color, color, color, color]
529
- when color.length == 2 # vert, horiz
530
- [color[0], color[1], color[0], color[1]]
531
- when color.length == 3 # top, horiz, bottom
532
- [color[0], color[1], color[2], color[1]]
533
- when color.length == 4 # top, right, bottom, left
534
- [color[0], color[1], color[2], color[3]]
535
- else
536
- raise ArgumentError, ":border_color must be a string " +
537
- "or an array [v,h] or [t,r,b,l]"
538
- end
539
- end
540
- alias_method :border_colors=, :border_color=
541
-
542
- def border_top_color
543
- @border_colors[0]
544
- end
545
-
546
- def border_top_color=(val)
547
- @border_colors[0] = val
548
- end
549
-
550
- def border_right_color
551
- @border_colors[1]
552
- end
553
-
554
- def border_right_color=(val)
555
- @border_colors[1] = val
556
- end
557
-
558
- def border_bottom_color
559
- @border_colors[2]
560
- end
561
-
562
- def border_bottom_color=(val)
563
- @border_colors[2] = val
564
- end
565
-
566
- def border_left_color
567
- @border_colors[3]
568
- end
569
-
570
- def border_left_color=(val)
571
- @border_colors[3] = val
572
- end
573
-
574
- # Sets border widths on this cell. The argument can be one of:
575
- #
576
- # * an integer (sets all widths)
577
- # * a two-element array [vertical, horizontal]
578
- # * a three-element array [top, horizontal, bottom]
579
- # * a four-element array [top, right, bottom, left]
580
- #
581
- def border_width=(width)
582
- @border_widths = case
583
- when width.nil?
584
- ["000000"] * 4
585
- when Numeric === width # all widths
586
- [width, width, width, width]
587
- when width.length == 2 # vert, horiz
588
- [width[0], width[1], width[0], width[1]]
589
- when width.length == 3 # top, horiz, bottom
590
- [width[0], width[1], width[2], width[1]]
591
- when width.length == 4 # top, right, bottom, left
592
- [width[0], width[1], width[2], width[3]]
593
- else
594
- raise ArgumentError, ":border_width must be a string " +
595
- "or an array [v,h] or [t,r,b,l]"
596
- end
597
- end
598
- alias_method :border_widths=, :border_width=
599
-
600
- def border_top_width
601
- @borders.include?(:top) ? @border_widths[0] : 0
602
- end
603
-
604
- def border_top_width=(val)
605
- @border_widths[0] = val
606
- end
607
-
608
- def border_right_width
609
- @borders.include?(:right) ? @border_widths[1] : 0
610
- end
611
-
612
- def border_right_width=(val)
613
- @border_widths[1] = val
614
- end
615
-
616
- def border_bottom_width
617
- @borders.include?(:bottom) ? @border_widths[2] : 0
618
- end
619
-
620
- def border_bottom_width=(val)
621
- @border_widths[2] = val
622
- end
623
-
624
- def border_left_width
625
- @borders.include?(:left) ? @border_widths[3] : 0
626
- end
627
-
628
- def border_left_width=(val)
629
- @border_widths[3] = val
630
- end
631
-
632
- # Sets the cell's minimum and maximum width. Deferred until requested
633
- # because padding and size can change.
634
- #
635
- def set_width_constraints
636
- @min_width ||= padding_left + padding_right
637
- @max_width ||= @pdf.bounds.width
638
- end
639
-
640
- # Sets border line style on this cell. The argument can be one of:
641
- #
642
- # Possible values are: :solid, :dashed, :dotted
643
- #
644
- # * one value (sets all lines)
645
- # * a two-element array [vertical, horizontal]
646
- # * a three-element array [top, horizontal, bottom]
647
- # * a four-element array [top, right, bottom, left]
648
- #
649
- def border_line=(line)
650
- @border_lines = case
651
- when line.nil?
652
- [:solid] * 4
653
- when line.length == 1 # all lines
654
- [line[0]] * 4
655
- when line.length == 2
656
- [line[0], line[1], line[0], line[1]]
657
- when line.length == 3
658
- [line[0], line[1], line[2], line[1]]
659
- when line.length == 4
660
- [line[0], line[1], line[2], line[3]]
661
- else
662
- raise ArgumentError, "border_line must be one of :solid, :dashed, "
663
- ":dotted or an array [v,h] or [t,r,b,l]"
664
- end
665
- end
666
- alias_method :border_lines=, :border_line=
667
-
668
- def border_top_line
669
- @borders.include?(:top) ? @border_lines[0] : 0
670
- end
671
-
672
- def border_top_line=(val)
673
- @border_lines[0] = val
674
- end
675
-
676
- def border_right_line
677
- @borders.include?(:right) ? @border_lines[1] : 0
678
- end
679
-
680
- def border_right_line=(val)
681
- @border_lines[1] = val
682
- end
683
-
684
- def border_bottom_line
685
- @borders.include?(:bottom) ? @border_lines[2] : 0
686
- end
687
-
688
- def border_bottom_line=(val)
689
- @border_lines[2] = val
690
- end
691
-
692
- def border_left_line
693
- @borders.include?(:left) ? @border_lines[3] : 0
694
- end
695
-
696
- def border_left_line=(val)
697
- @border_lines[3] = val
698
- end
699
-
700
- # Draws the cell's background color.
701
- #
702
- def draw_background(pt)
703
- if defined?(@background_color) && @background_color
704
- @pdf.mask(:fill_color) do
705
- @pdf.fill_color @background_color
706
- @pdf.fill_rectangle pt, width, height
707
- end
708
- end
709
- end
710
-
711
- # Draws borders around the cell. Borders are centered on the bounds of
712
- # the cell outside of any padding, so the caller is responsible for
713
- # setting appropriate padding to ensure the border does not overlap with
714
- # cell content.
715
- #
716
- def draw_borders(pt)
717
- x, y = pt
718
-
719
- @pdf.mask(:line_width, :stroke_color) do
720
- @borders.each do |border|
721
- idx = {:top => 0, :right => 1, :bottom => 2, :left => 3}[border]
722
- border_color = @border_colors[idx]
723
- border_width = @border_widths[idx]
724
- border_line = @border_lines[idx]
725
-
726
- next if border_width <= 0
727
-
728
- # Left and right borders are drawn one-half border beyond the center
729
- # of the corner, so that the corners end up square.
730
- from, to = case border
731
- when :top
732
- [[x, y], [x+width, y]]
733
- when :bottom
734
- [[x, y-height], [x+width, y-height]]
735
- when :left
736
- [[x, y + (border_top_width / 2.0)],
737
- [x, y - height - (border_bottom_width / 2.0)]]
738
- when :right
739
- [[x+width, y + (border_top_width / 2.0)],
740
- [x+width, y - height - (border_bottom_width / 2.0)]]
741
- end
742
-
743
- case border_line
744
- when :dashed
745
- @pdf.dash border_width * 4
746
- when :dotted
747
- @pdf.dash border_width, :space => border_width * 2
748
- when :solid
749
- # normal line style
750
- else
751
- raise ArgumentError, "border_line must be :solid, :dotted or" +
752
- " :dashed"
753
- end
754
-
755
- @pdf.line_width = border_width
756
- @pdf.stroke_color = border_color
757
- @pdf.stroke_line(from, to)
758
- @pdf.undash
759
- end
760
- end
761
- end
762
-
763
- # Draws cell content within the cell's bounding box. Must be implemented
764
- # in subclasses.
765
- #
766
- def draw_content
767
- raise NotImplementedError, "subclasses must implement draw_content"
768
- end
769
-
770
- end
771
- end
772
- end