nurettin-prawn 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (303) hide show
  1. data/COPYING +2 -0
  2. data/GPLv2 +340 -0
  3. data/GPLv3 +674 -0
  4. data/Gemfile +18 -0
  5. data/LICENSE +56 -0
  6. data/README.md +98 -0
  7. data/Rakefile +45 -0
  8. data/data/encodings/win_ansi.txt +29 -0
  9. data/data/fonts/Action Man.dfont +0 -0
  10. data/data/fonts/Activa.ttf +0 -0
  11. data/data/fonts/Chalkboard.ttf +0 -0
  12. data/data/fonts/Courier-Bold.afm +342 -0
  13. data/data/fonts/Courier-BoldOblique.afm +342 -0
  14. data/data/fonts/Courier-Oblique.afm +342 -0
  15. data/data/fonts/Courier.afm +342 -0
  16. data/data/fonts/DejaVuSans.ttf +0 -0
  17. data/data/fonts/Dustismo_Roman.ttf +0 -0
  18. data/data/fonts/Helvetica-Bold.afm +2827 -0
  19. data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  20. data/data/fonts/Helvetica-Oblique.afm +3051 -0
  21. data/data/fonts/Helvetica.afm +3051 -0
  22. data/data/fonts/MustRead.html +19 -0
  23. data/data/fonts/Symbol.afm +213 -0
  24. data/data/fonts/Times-Bold.afm +2588 -0
  25. data/data/fonts/Times-BoldItalic.afm +2384 -0
  26. data/data/fonts/Times-Italic.afm +2667 -0
  27. data/data/fonts/Times-Roman.afm +2419 -0
  28. data/data/fonts/ZapfDingbats.afm +225 -0
  29. data/data/fonts/comicsans.ttf +0 -0
  30. data/data/fonts/gkai00mp.ttf +0 -0
  31. data/data/images/16bit.alpha +0 -0
  32. data/data/images/16bit.dat +0 -0
  33. data/data/images/16bit.png +0 -0
  34. data/data/images/arrow.png +0 -0
  35. data/data/images/arrow2.png +0 -0
  36. data/data/images/barcode_issue.png +0 -0
  37. data/data/images/dice.alpha +0 -0
  38. data/data/images/dice.dat +0 -0
  39. data/data/images/dice.png +0 -0
  40. data/data/images/dice_interlaced.png +0 -0
  41. data/data/images/fractal.jpg +0 -0
  42. data/data/images/letterhead.jpg +0 -0
  43. data/data/images/page_white_text.alpha +0 -0
  44. data/data/images/page_white_text.dat +0 -0
  45. data/data/images/page_white_text.png +0 -0
  46. data/data/images/pigs.jpg +0 -0
  47. data/data/images/prawn.png +0 -0
  48. data/data/images/rails.dat +0 -0
  49. data/data/images/rails.png +0 -0
  50. data/data/images/ruport.png +0 -0
  51. data/data/images/ruport_data.dat +0 -0
  52. data/data/images/ruport_transparent.png +0 -0
  53. data/data/images/ruport_type0.png +0 -0
  54. data/data/images/stef.jpg +0 -0
  55. data/data/images/tru256.bmp +0 -0
  56. data/data/images/web-links.dat +1 -0
  57. data/data/images/web-links.png +0 -0
  58. data/data/pdfs/complex_template.pdf +0 -0
  59. data/data/pdfs/contains_ttf_font.pdf +0 -0
  60. data/data/pdfs/encrypted.pdf +0 -0
  61. data/data/pdfs/form.pdf +820 -0
  62. data/data/pdfs/hexagon.pdf +61 -0
  63. data/data/pdfs/indirect_reference.pdf +86 -0
  64. data/data/pdfs/multipage_template.pdf +127 -0
  65. data/data/pdfs/nested_pages.pdf +118 -0
  66. data/data/pdfs/page_without_mediabox.pdf +193 -0
  67. data/data/pdfs/resources_as_indirect_object.pdf +83 -0
  68. data/data/pdfs/two_hexagons.pdf +90 -0
  69. data/data/pdfs/version_1_6.pdf +61 -0
  70. data/data/shift_jis_text.txt +1 -0
  71. data/lib/prawn.rb +29 -0
  72. data/lib/prawn/compatibility.rb +87 -0
  73. data/lib/prawn/core.rb +87 -0
  74. data/lib/prawn/core/annotations.rb +61 -0
  75. data/lib/prawn/core/byte_string.rb +9 -0
  76. data/lib/prawn/core/destinations.rb +90 -0
  77. data/lib/prawn/core/document_state.rb +79 -0
  78. data/lib/prawn/core/literal_string.rb +16 -0
  79. data/lib/prawn/core/name_tree.rb +177 -0
  80. data/lib/prawn/core/object_store.rb +320 -0
  81. data/lib/prawn/core/page.rb +212 -0
  82. data/lib/prawn/core/pdf_object.rb +125 -0
  83. data/lib/prawn/core/reference.rb +119 -0
  84. data/lib/prawn/core/text.rb +268 -0
  85. data/lib/prawn/core/text/formatted/arranger.rb +294 -0
  86. data/lib/prawn/core/text/formatted/line_wrap.rb +288 -0
  87. data/lib/prawn/core/text/formatted/wrap.rb +153 -0
  88. data/lib/prawn/document.rb +707 -0
  89. data/lib/prawn/document/bounding_box.rb +510 -0
  90. data/lib/prawn/document/column_box.rb +132 -0
  91. data/lib/prawn/document/graphics_state.rb +136 -0
  92. data/lib/prawn/document/internals.rb +173 -0
  93. data/lib/prawn/document/page_geometry.rb +136 -0
  94. data/lib/prawn/document/snapshot.rb +89 -0
  95. data/lib/prawn/document/span.rb +55 -0
  96. data/lib/prawn/encoding.rb +121 -0
  97. data/lib/prawn/errors.rb +99 -0
  98. data/lib/prawn/font.rb +386 -0
  99. data/lib/prawn/font/afm.rb +203 -0
  100. data/lib/prawn/font/dfont.rb +42 -0
  101. data/lib/prawn/font/ttf.rb +343 -0
  102. data/lib/prawn/graphics.rb +523 -0
  103. data/lib/prawn/graphics/cap_style.rb +46 -0
  104. data/lib/prawn/graphics/color.rb +231 -0
  105. data/lib/prawn/graphics/dash.rb +82 -0
  106. data/lib/prawn/graphics/join_style.rb +47 -0
  107. data/lib/prawn/graphics/patterns.rb +137 -0
  108. data/lib/prawn/graphics/transformation.rb +156 -0
  109. data/lib/prawn/graphics/transparency.rb +99 -0
  110. data/lib/prawn/images.rb +196 -0
  111. data/lib/prawn/images/image.rb +65 -0
  112. data/lib/prawn/images/jpg.rb +85 -0
  113. data/lib/prawn/images/png.rb +362 -0
  114. data/lib/prawn/layout.rb +20 -0
  115. data/lib/prawn/layout/grid.rb +259 -0
  116. data/lib/prawn/measurement_extensions.rb +46 -0
  117. data/lib/prawn/measurements.rb +71 -0
  118. data/lib/prawn/outline.rb +326 -0
  119. data/lib/prawn/repeater.rb +122 -0
  120. data/lib/prawn/security.rb +269 -0
  121. data/lib/prawn/soft_mask.rb +94 -0
  122. data/lib/prawn/stamp.rb +134 -0
  123. data/lib/prawn/table.rb +609 -0
  124. data/lib/prawn/table/cell.rb +776 -0
  125. data/lib/prawn/table/cell/image.rb +70 -0
  126. data/lib/prawn/table/cell/in_table.rb +27 -0
  127. data/lib/prawn/table/cell/span_dummy.rb +88 -0
  128. data/lib/prawn/table/cell/subtable.rb +65 -0
  129. data/lib/prawn/table/cell/text.rb +152 -0
  130. data/lib/prawn/table/cells.rb +260 -0
  131. data/lib/prawn/text.rb +420 -0
  132. data/lib/prawn/text/box.rb +141 -0
  133. data/lib/prawn/text/formatted.rb +4 -0
  134. data/lib/prawn/text/formatted/box.rb +563 -0
  135. data/lib/prawn/text/formatted/fragment.rb +253 -0
  136. data/lib/prawn/text/formatted/parser.rb +217 -0
  137. data/lib/prawn/utilities.rb +44 -0
  138. data/manual/basic_concepts/adding_pages.rb +27 -0
  139. data/manual/basic_concepts/basic_concepts.rb +34 -0
  140. data/manual/basic_concepts/creation.rb +39 -0
  141. data/manual/basic_concepts/cursor.rb +33 -0
  142. data/manual/basic_concepts/measurement.rb +25 -0
  143. data/manual/basic_concepts/origin.rb +38 -0
  144. data/manual/basic_concepts/other_cursor_helpers.rb +40 -0
  145. data/manual/bounding_box/bounding_box.rb +39 -0
  146. data/manual/bounding_box/bounds.rb +49 -0
  147. data/manual/bounding_box/canvas.rb +24 -0
  148. data/manual/bounding_box/creation.rb +23 -0
  149. data/manual/bounding_box/indentation.rb +46 -0
  150. data/manual/bounding_box/nesting.rb +45 -0
  151. data/manual/bounding_box/russian_boxes.rb +40 -0
  152. data/manual/bounding_box/stretchy.rb +31 -0
  153. data/manual/document_and_page_options/background.rb +27 -0
  154. data/manual/document_and_page_options/document_and_page_options.rb +31 -0
  155. data/manual/document_and_page_options/metadata.rb +23 -0
  156. data/manual/document_and_page_options/page_margins.rb +38 -0
  157. data/manual/document_and_page_options/page_size.rb +34 -0
  158. data/manual/example_file.rb +116 -0
  159. data/manual/example_helper.rb +430 -0
  160. data/manual/example_package.rb +53 -0
  161. data/manual/example_section.rb +46 -0
  162. data/manual/graphics/circle_and_ellipse.rb +22 -0
  163. data/manual/graphics/color.rb +24 -0
  164. data/manual/graphics/common_lines.rb +28 -0
  165. data/manual/graphics/fill_and_stroke.rb +42 -0
  166. data/manual/graphics/fill_rules.rb +37 -0
  167. data/manual/graphics/gradients.rb +37 -0
  168. data/manual/graphics/graphics.rb +58 -0
  169. data/manual/graphics/helper.rb +17 -0
  170. data/manual/graphics/line_width.rb +35 -0
  171. data/manual/graphics/lines_and_curves.rb +41 -0
  172. data/manual/graphics/polygon.rb +29 -0
  173. data/manual/graphics/rectangle.rb +21 -0
  174. data/manual/graphics/rotate.rb +28 -0
  175. data/manual/graphics/scale.rb +41 -0
  176. data/manual/graphics/soft_masks.rb +46 -0
  177. data/manual/graphics/stroke_cap.rb +31 -0
  178. data/manual/graphics/stroke_dash.rb +43 -0
  179. data/manual/graphics/stroke_join.rb +30 -0
  180. data/manual/graphics/translate.rb +29 -0
  181. data/manual/graphics/transparency.rb +35 -0
  182. data/manual/images/absolute_position.rb +23 -0
  183. data/manual/images/fit.rb +21 -0
  184. data/manual/images/horizontal.rb +25 -0
  185. data/manual/images/images.rb +40 -0
  186. data/manual/images/plain_image.rb +18 -0
  187. data/manual/images/scale.rb +22 -0
  188. data/manual/images/vertical.rb +28 -0
  189. data/manual/images/width_and_height.rb +25 -0
  190. data/manual/layout/boxes.rb +27 -0
  191. data/manual/layout/content.rb +25 -0
  192. data/manual/layout/layout.rb +28 -0
  193. data/manual/layout/simple_grid.rb +23 -0
  194. data/manual/manual/cover.rb +26 -0
  195. data/manual/manual/foreword.rb +13 -0
  196. data/manual/manual/how_to_read_this_manual.rb +41 -0
  197. data/manual/manual/manual.rb +36 -0
  198. data/manual/outline/add_subsection_to.rb +61 -0
  199. data/manual/outline/insert_section_after.rb +47 -0
  200. data/manual/outline/outline.rb +32 -0
  201. data/manual/outline/sections_and_pages.rb +67 -0
  202. data/manual/repeatable_content/page_numbering.rb +54 -0
  203. data/manual/repeatable_content/repeatable_content.rb +31 -0
  204. data/manual/repeatable_content/repeater.rb +55 -0
  205. data/manual/repeatable_content/stamp.rb +41 -0
  206. data/manual/security/encryption.rb +31 -0
  207. data/manual/security/permissions.rb +38 -0
  208. data/manual/security/security.rb +28 -0
  209. data/manual/syntax_highlight.rb +52 -0
  210. data/manual/table/basic_block.rb +53 -0
  211. data/manual/table/before_rendering_page.rb +26 -0
  212. data/manual/table/cell_border_lines.rb +24 -0
  213. data/manual/table/cell_borders_and_bg.rb +31 -0
  214. data/manual/table/cell_dimensions.rb +30 -0
  215. data/manual/table/cell_text.rb +38 -0
  216. data/manual/table/column_widths.rb +30 -0
  217. data/manual/table/content_and_subtables.rb +39 -0
  218. data/manual/table/creation.rb +27 -0
  219. data/manual/table/filtering.rb +36 -0
  220. data/manual/table/flow_and_header.rb +17 -0
  221. data/manual/table/image_cells.rb +33 -0
  222. data/manual/table/position.rb +29 -0
  223. data/manual/table/row_colors.rb +20 -0
  224. data/manual/table/span.rb +30 -0
  225. data/manual/table/style.rb +22 -0
  226. data/manual/table/table.rb +52 -0
  227. data/manual/table/width.rb +27 -0
  228. data/manual/templates/full_template.rb +23 -0
  229. data/manual/templates/page_template.rb +47 -0
  230. data/manual/templates/templates.rb +26 -0
  231. data/manual/text/alignment.rb +44 -0
  232. data/manual/text/color.rb +24 -0
  233. data/manual/text/column_box.rb +32 -0
  234. data/manual/text/fallback_fonts.rb +37 -0
  235. data/manual/text/font.rb +41 -0
  236. data/manual/text/font_size.rb +45 -0
  237. data/manual/text/font_style.rb +23 -0
  238. data/manual/text/formatted_callbacks.rb +60 -0
  239. data/manual/text/formatted_text.rb +50 -0
  240. data/manual/text/free_flowing_text.rb +51 -0
  241. data/manual/text/group.rb +29 -0
  242. data/manual/text/inline.rb +43 -0
  243. data/manual/text/kerning_and_character_spacing.rb +39 -0
  244. data/manual/text/leading.rb +25 -0
  245. data/manual/text/line_wrapping.rb +41 -0
  246. data/manual/text/paragraph_indentation.rb +26 -0
  247. data/manual/text/positioned_text.rb +38 -0
  248. data/manual/text/registering_families.rb +48 -0
  249. data/manual/text/rendering_and_color.rb +37 -0
  250. data/manual/text/right_to_left_text.rb +43 -0
  251. data/manual/text/rotation.rb +43 -0
  252. data/manual/text/single_usage.rb +37 -0
  253. data/manual/text/text.rb +75 -0
  254. data/manual/text/text_box_excess.rb +32 -0
  255. data/manual/text/text_box_extensions.rb +45 -0
  256. data/manual/text/text_box_overflow.rb +44 -0
  257. data/manual/text/utf8.rb +28 -0
  258. data/manual/text/win_ansi_charset.rb +59 -0
  259. data/prawn.gemspec +46 -0
  260. data/spec/annotations_spec.rb +90 -0
  261. data/spec/bounding_box_spec.rb +493 -0
  262. data/spec/cell_spec.rb +584 -0
  263. data/spec/column_box_spec.rb +33 -0
  264. data/spec/data/curves.pdf +66 -0
  265. data/spec/destinations_spec.rb +15 -0
  266. data/spec/document_spec.rb +736 -0
  267. data/spec/extensions/encoding_helpers.rb +6 -0
  268. data/spec/extensions/mocha.rb +44 -0
  269. data/spec/font_spec.rb +433 -0
  270. data/spec/formatted_text_arranger_spec.rb +421 -0
  271. data/spec/formatted_text_box_spec.rb +640 -0
  272. data/spec/formatted_text_fragment_spec.rb +298 -0
  273. data/spec/graphics_spec.rb +651 -0
  274. data/spec/grid_spec.rb +85 -0
  275. data/spec/images_spec.rb +140 -0
  276. data/spec/inline_formatted_text_parser_spec.rb +515 -0
  277. data/spec/jpg_spec.rb +25 -0
  278. data/spec/line_wrap_spec.rb +333 -0
  279. data/spec/measurement_units_spec.rb +23 -0
  280. data/spec/name_tree_spec.rb +112 -0
  281. data/spec/object_store_spec.rb +170 -0
  282. data/spec/outline_spec.rb +426 -0
  283. data/spec/pdf_object_spec.rb +172 -0
  284. data/spec/png_spec.rb +240 -0
  285. data/spec/reference_spec.rb +105 -0
  286. data/spec/repeater_spec.rb +158 -0
  287. data/spec/security_spec.rb +126 -0
  288. data/spec/snapshot_spec.rb +186 -0
  289. data/spec/soft_mask_spec.rb +117 -0
  290. data/spec/span_spec.rb +49 -0
  291. data/spec/spec_helper.rb +36 -0
  292. data/spec/stamp_spec.rb +159 -0
  293. data/spec/stroke_styles_spec.rb +193 -0
  294. data/spec/table_spec.rb +1209 -0
  295. data/spec/template_spec.rb +351 -0
  296. data/spec/text_at_spec.rb +129 -0
  297. data/spec/text_box_spec.rb +1029 -0
  298. data/spec/text_rendering_mode_spec.rb +45 -0
  299. data/spec/text_spacing_spec.rb +93 -0
  300. data/spec/text_spec.rb +421 -0
  301. data/spec/text_with_inline_formatting_spec.rb +35 -0
  302. data/spec/transparency_spec.rb +89 -0
  303. metadata +544 -0
@@ -0,0 +1,70 @@
1
+ # encoding: utf-8
2
+
3
+ # image.rb: Table image cells.
4
+ #
5
+ # Copyright September 2010, Brad Ediger. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ module Prawn
9
+ class Table
10
+ class Cell
11
+
12
+ # A Cell that contains another table.
13
+ #
14
+ class Image < Cell
15
+
16
+ def initialize(pdf, point, options={})
17
+ @image_options = {}
18
+ super
19
+
20
+ @pdf_object, @image_info = @pdf.build_image_object(@file)
21
+ @natural_width, @natural_height = @image_info.calc_image_dimensions(
22
+ @image_options)
23
+ end
24
+
25
+ def image=(file)
26
+ @file = file
27
+ end
28
+
29
+ def scale=(s)
30
+ @image_options[:scale] = s
31
+ end
32
+
33
+ def fit=(f)
34
+ @image_options[:fit] = f
35
+ end
36
+
37
+ def image_height=(h)
38
+ @image_options[:height] = h
39
+ end
40
+
41
+ def image_width=(w)
42
+ @image_options[:width] = w
43
+ end
44
+
45
+ def position=(p)
46
+ @image_options[:position] = p
47
+ end
48
+
49
+ def vposition=(vp)
50
+ @image_options[:vposition] = vp
51
+ end
52
+
53
+ def natural_content_width
54
+ @natural_width
55
+ end
56
+
57
+ def natural_content_height
58
+ @natural_height
59
+ end
60
+
61
+ # Draw the image on the page.
62
+ #
63
+ def draw_content
64
+ @pdf.embed_image(@pdf_object, @image_info, @image_options)
65
+ end
66
+
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+
3
+ # Accessors for using a Cell inside a Table.
4
+
5
+ module Prawn
6
+ class Table
7
+ class Cell
8
+
9
+ # This module extends Cell objects when they are used in a table (as
10
+ # opposed to standalone). Its properties apply to cells-in-tables but not
11
+ # cells themselves.
12
+ #
13
+ module InTable
14
+
15
+ # Row number (0-based).
16
+ #
17
+ attr_accessor :row
18
+
19
+ # Column number (0-based).
20
+ #
21
+ attr_accessor :column
22
+
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,88 @@
1
+ # encoding: utf-8
2
+
3
+ # span_dummy.rb: Placeholder for non-master spanned cells.
4
+ #
5
+ # Copyright December 2011, Brad Ediger. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ module Prawn
9
+ class Table
10
+ class Cell
11
+
12
+ # A Cell object used to represent all but the topmost cell in a span
13
+ # group.
14
+ #
15
+ class SpanDummy < Cell
16
+ def initialize(pdf, master_cell)
17
+ super(pdf, [0, pdf.cursor])
18
+ @master_cell = master_cell
19
+ @padding = [0, 0, 0, 0]
20
+ end
21
+
22
+ # By default, a span dummy will never increase the height demand.
23
+ #
24
+ def natural_content_height
25
+ 0
26
+ end
27
+
28
+ # By default, a span dummy will never increase the width demand.
29
+ #
30
+ def natural_content_width
31
+ 0
32
+ end
33
+
34
+ def avg_spanned_min_width
35
+ @master_cell.avg_spanned_min_width
36
+ end
37
+
38
+ # Dummy cells have nothing to draw.
39
+ #
40
+ def draw_borders(pt)
41
+ end
42
+
43
+ # Dummy cells have nothing to draw.
44
+ #
45
+ def draw_bounded_content(pt)
46
+ end
47
+
48
+ def padding_right=(val)
49
+ @master_cell.padding_right = val if rightmost?
50
+ end
51
+
52
+ def padding_bottom=(val)
53
+ @master_cell.padding_bottom = val if bottommost?
54
+ end
55
+
56
+ def border_right_color=(val)
57
+ @master_cell.border_right_color = val if rightmost?
58
+ end
59
+
60
+ def border_bottom_color=(val)
61
+ @master_cell.border_bottom_color = val if bottommost?
62
+ end
63
+
64
+ def border_right_width=(val)
65
+ @master_cell.border_right_width = val if rightmost?
66
+ end
67
+
68
+ def border_bottom_width=(val)
69
+ @master_cell.border_bottom_width = val if bottommost?
70
+ end
71
+
72
+ private
73
+
74
+ # Are we on the right border of the span?
75
+ #
76
+ def rightmost?
77
+ @column == @master_cell.column + @master_cell.colspan - 1
78
+ end
79
+
80
+ # Are we on the bottom border of the span?
81
+ #
82
+ def bottommost?
83
+ @row == @master_cell.row + @master_cell.rowspan - 1
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+
3
+ # subtable.rb: Yo dawg.
4
+ #
5
+ # Copyright January 2010, Brad Ediger. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ module Prawn
9
+ class Table
10
+ class Cell
11
+
12
+ # A Cell that contains another table.
13
+ #
14
+ class Subtable < Cell
15
+
16
+ attr_reader :subtable
17
+
18
+ def initialize(pdf, point, options={})
19
+ super
20
+ @subtable = options[:content]
21
+
22
+ # Subtable padding defaults to zero
23
+ @padding = [0, 0, 0, 0]
24
+ end
25
+
26
+ # Sets the text color of the entire subtable.
27
+ #
28
+ def text_color=(color)
29
+ @subtable.cells.text_color = color
30
+ end
31
+
32
+ # Proxied to subtable.
33
+ #
34
+ def natural_content_width
35
+ @subtable.cells.width
36
+ end
37
+
38
+ # Proxied to subtable.
39
+ #
40
+ def min_width
41
+ @subtable.cells.min_width
42
+ end
43
+
44
+ # Proxied to subtable.
45
+ #
46
+ def max_width
47
+ @subtable.cells.max_width
48
+ end
49
+
50
+ # Proxied to subtable.
51
+ #
52
+ def natural_content_height
53
+ @subtable.cells.height
54
+ end
55
+
56
+ # Draws the subtable.
57
+ #
58
+ def draw_content
59
+ @subtable.draw
60
+ end
61
+
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,152 @@
1
+ # encoding: utf-8
2
+
3
+ # text.rb: Text table cells.
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
+ module Prawn
9
+ class Table
10
+ class Cell
11
+
12
+ # A Cell that contains text. Has some limited options to set font family,
13
+ # size, and style.
14
+ #
15
+ class Text < Cell
16
+
17
+ TextOptions = [:inline_format, :kerning, :size, :align, :valign,
18
+ :rotate, :rotate_around, :leading, :single_line, :skip_encoding,
19
+ :overflow, :min_font_size]
20
+
21
+ TextOptions.each do |option|
22
+ define_method("#{option}=") { |v| @text_options[option] = v }
23
+ define_method(option) { @text_options[option] }
24
+ end
25
+
26
+ attr_writer :font, :text_color
27
+
28
+ def initialize(pdf, point, options={})
29
+ @text_options = {}
30
+ super
31
+ end
32
+
33
+ # Returns the font that will be used to draw this cell.
34
+ #
35
+ def font
36
+ with_font { @pdf.font }
37
+ end
38
+
39
+ # Sets the style of the font in use. Equivalent to the Text::Box
40
+ # +style+ option, but we already have a style method.
41
+ #
42
+ def font_style=(style)
43
+ @text_options[:style] = style
44
+ end
45
+
46
+ # Returns the width of this text with no wrapping. This will be far off
47
+ # from the final width if the text is long.
48
+ #
49
+ def natural_content_width
50
+ @natural_content_width ||= [styled_width_of(@content), @pdf.bounds.width].min
51
+ end
52
+
53
+ # Returns the natural height of this block of text, wrapped to the
54
+ # preset width.
55
+ #
56
+ def natural_content_height
57
+ with_font do
58
+ b = text_box(:width => spanned_content_width + FPTolerance)
59
+ b.render(:dry_run => true)
60
+ b.height + b.line_gap
61
+ end
62
+ end
63
+
64
+ # Draws the text content into its bounding box.
65
+ #
66
+ def draw_content
67
+ with_font do
68
+ @pdf.move_down((@pdf.font.line_gap + @pdf.font.descender)/2)
69
+ with_text_color do
70
+ text_box(:width => spanned_content_width + FPTolerance,
71
+ :height => spanned_content_height + FPTolerance,
72
+ :at => [0, @pdf.cursor]).render
73
+ end
74
+ end
75
+ end
76
+
77
+ def set_width_constraints
78
+ # Sets a reasonable minimum width. If the cell has any content, make
79
+ # sure we have enough width to be at least one character wide. This is
80
+ # a bit of a hack, but it should work well enough.
81
+ unless @min_width
82
+ min_content_width = [natural_content_width, styled_width_of_single_character].min
83
+ @min_width = padding_left + padding_right + min_content_width
84
+ super
85
+ end
86
+ end
87
+
88
+ protected
89
+
90
+ def with_font
91
+ @pdf.save_font do
92
+ options = {}
93
+ options[:style] = @text_options[:style] if @text_options[:style]
94
+
95
+ @pdf.font(@font || @pdf.font.name, options)
96
+
97
+ yield
98
+ end
99
+ end
100
+
101
+ def with_text_color
102
+ if @text_color
103
+ begin
104
+ old_color = @pdf.fill_color || '000000'
105
+ @pdf.fill_color(@text_color)
106
+ yield
107
+ ensure
108
+ @pdf.fill_color(old_color)
109
+ end
110
+ else
111
+ yield
112
+ end
113
+ end
114
+
115
+ def text_box(extra_options={})
116
+ if @text_options[:inline_format]
117
+ options = @text_options.dup
118
+ options.delete(:inline_format)
119
+ options.merge!(extra_options)
120
+ options[:document] = @pdf
121
+
122
+ array = ::Prawn::Text::Formatted::Parser.to_array(@content)
123
+ ::Prawn::Text::Formatted::Box.new(array, options)
124
+ else
125
+ ::Prawn::Text::Box.new(@content, @text_options.merge(extra_options).
126
+ merge(:document => @pdf))
127
+ end
128
+ end
129
+
130
+ # Returns the width of +text+ under the given text options.
131
+ #
132
+ def styled_width_of(text)
133
+ @pdf.width_of(text, @text_options)
134
+ end
135
+
136
+ private
137
+
138
+ # Returns the greatest possible width of any single character
139
+ # under the given text options.
140
+ # (We use this to determine the minimum width of a table cell)
141
+ # (Although we currently determine this by measuring "M", it should really
142
+ # use whichever character is widest under the current font)
143
+ #
144
+ def styled_width_of_single_character
145
+ key = (@text_options[:style] == :bold) ? :bold_char_width : :plain_char_width
146
+ cache = Thread.current[key] ||= {}
147
+ cache[@pdf.font] ||= styled_width_of("M")
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,260 @@
1
+ # encoding: utf-8
2
+
3
+ # cells.rb: Methods for accessing rows, columns, and cells of a Prawn::Table.
4
+ #
5
+ # Copyright December 2009, Brad Ediger. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+ module Prawn
10
+ class Table
11
+
12
+ # Selects the given rows (0-based) for styling. Returns a Cells object --
13
+ # see the documentation on Cells for things you can do with cells.
14
+ #
15
+ def rows(row_spec)
16
+ cells.rows(row_spec)
17
+ end
18
+ alias_method :row, :rows
19
+
20
+ # Selects the given columns (0-based) for styling. Returns a Cells object
21
+ # -- see the documentation on Cells for things you can do with cells.
22
+ #
23
+ def columns(col_spec)
24
+ cells.columns(col_spec)
25
+ end
26
+ alias_method :column, :columns
27
+
28
+ # Represents a selection of cells to be styled. Operations on a CellProxy
29
+ # can be chained, and cell properties can be set one-for-all on the proxy.
30
+ #
31
+ # To set vertical borders only:
32
+ #
33
+ # table.cells.borders = [:left, :right]
34
+ #
35
+ # To highlight a rectangular area of the table:
36
+ #
37
+ # table.rows(1..3).columns(2..4).background_color = 'ff0000'
38
+ #
39
+ class Cells < Array
40
+
41
+ # Limits selection to the given row or rows. +row_spec+ can be anything
42
+ # that responds to the === operator selecting a set of 0-based row
43
+ # numbers; most commonly a number or a range.
44
+ #
45
+ # table.row(0) # selects first row
46
+ # table.rows(3..4) # selects rows four and five
47
+ #
48
+ def rows(row_spec)
49
+ index_cells unless @indexed
50
+ row_spec = transform_spec(row_spec, @first_row, @row_count)
51
+ Cells.new(@rows[row_spec] ||= select { |c|
52
+ row_spec.respond_to?(:include?) ?
53
+ row_spec.include?(c.row) : row_spec === c.row })
54
+ end
55
+ alias_method :row, :rows
56
+
57
+ # Returns the number of rows in the list.
58
+ #
59
+ def row_count
60
+ index_cells unless @indexed
61
+ @row_count
62
+ end
63
+
64
+ # Limits selection to the given column or columns. +col_spec+ can be
65
+ # anything that responds to the === operator selecting a set of 0-based
66
+ # column numbers; most commonly a number or a range.
67
+ #
68
+ # table.column(0) # selects first column
69
+ # table.columns(3..4) # selects columns four and five
70
+ #
71
+ def columns(col_spec)
72
+ index_cells unless @indexed
73
+ col_spec = transform_spec(col_spec, @first_column, @column_count)
74
+ Cells.new(@columns[col_spec] ||= select { |c|
75
+ col_spec.respond_to?(:include?) ?
76
+ col_spec.include?(c.column) : col_spec === c.column })
77
+ end
78
+ alias_method :column, :columns
79
+
80
+ # Returns the number of columns in the list.
81
+ #
82
+ def column_count
83
+ index_cells unless @indexed
84
+ @column_count
85
+ end
86
+
87
+ # Allows you to filter the given cells by arbitrary properties.
88
+ #
89
+ # table.column(4).filter { |cell| cell.content =~ /Yes/ }.
90
+ # background_color = '00ff00'
91
+ #
92
+ def filter(&block)
93
+ Cells.new(select(&block))
94
+ end
95
+
96
+ # Retrieves a cell based on its 0-based row and column. Returns an
97
+ # individual Cell, not a Cells collection.
98
+ #
99
+ # table.cells[0, 0].content # => "First cell content"
100
+ #
101
+ def [](row, col)
102
+ return nil if empty?
103
+ index_cells unless @indexed
104
+ row_array, col_array = @rows[@first_row + row] || [], @columns[@first_column + col] || []
105
+ if row_array.length < col_array.length
106
+ row_array.find { |c| c.column == @first_column + col }
107
+ else
108
+ col_array.find { |c| c.row == @first_row + row }
109
+ end
110
+ end
111
+
112
+ # Puts a cell in the collection at the given position. Internal use only.
113
+ #
114
+ def []=(row, col, cell) # :nodoc:
115
+ cell.extend(Cell::InTable)
116
+ cell.row = row
117
+ cell.column = col
118
+
119
+ if @indexed
120
+ (@rows[row] ||= []) << cell
121
+ (@columns[col] ||= []) << cell
122
+ @first_row = row if !@first_row || row < @first_row
123
+ @first_column = col if !@first_column || col < @first_column
124
+ @row_count = @rows.size
125
+ @column_count = @columns.size
126
+ end
127
+
128
+ self << cell
129
+ end
130
+
131
+ # Supports setting multiple properties at once.
132
+ #
133
+ # table.cells.style(:padding => 0, :border_width => 2)
134
+ #
135
+ # is the same as:
136
+ #
137
+ # table.cells.padding = 0
138
+ # table.cells.border_width = 2
139
+ #
140
+ # You can also pass a block, which will be called for each cell in turn.
141
+ # This allows you to set more complicated properties:
142
+ #
143
+ # table.cells.style { |cell| cell.border_width += 12 }
144
+ #
145
+ def style(options={}, &block)
146
+ each do |cell|
147
+ next if cell.is_a?(Cell::SpanDummy)
148
+ cell.style(options, &block)
149
+ end
150
+ end
151
+
152
+ # Returns the total width of all columns in the selected set.
153
+ #
154
+ def width
155
+ widths = {}
156
+ each do |cell|
157
+ index = cell.column
158
+ per_cell_width = cell.width_ignoring_span.to_f / cell.colspan
159
+ cell.colspan.times do |n|
160
+ widths[cell.column+n] = [widths[cell.column+n], per_cell_width].
161
+ compact.max
162
+ end
163
+ end
164
+ widths.values.inject(0, &:+)
165
+ end
166
+
167
+ # Returns minimum width required to contain cells in the set.
168
+ #
169
+ def min_width
170
+ aggregate_cell_values(:column, :avg_spanned_min_width, :max)
171
+ end
172
+
173
+ # Returns maximum width that can contain cells in the set.
174
+ #
175
+ def max_width
176
+ aggregate_cell_values(:column, :max_width_ignoring_span, :min)
177
+ end
178
+
179
+ # Returns the total height of all rows in the selected set.
180
+ #
181
+ def height
182
+ aggregate_cell_values(:row, :height_ignoring_span, :max)
183
+ end
184
+
185
+ # Supports setting arbitrary properties on a group of cells.
186
+ #
187
+ # table.cells.row(3..6).background_color = 'cc0000'
188
+ #
189
+ def method_missing(id, *args, &block)
190
+ if id.to_s =~ /=\z/
191
+ each { |c| c.send(id, *args, &block) if c.respond_to?(id) }
192
+ else
193
+ super
194
+ end
195
+ end
196
+
197
+ protected
198
+
199
+ # Defers indexing until rows() or columns() is actually called on the
200
+ # Cells object. Without this, we would needlessly index the leaf nodes of
201
+ # the object graph, the ones that are only there to be iterated over.
202
+ #
203
+ # Make sure to call this before using @rows or @columns.
204
+ #
205
+ def index_cells
206
+ @rows = {}
207
+ @columns = {}
208
+
209
+ each do |cell|
210
+ @rows[cell.row] ||= []
211
+ @rows[cell.row] << cell
212
+
213
+ @columns[cell.column] ||= []
214
+ @columns[cell.column] << cell
215
+ end
216
+
217
+ @first_row = @rows.keys.min
218
+ @first_column = @columns.keys.min
219
+
220
+ @row_count = @rows.size
221
+ @column_count = @columns.size
222
+
223
+ @indexed = true
224
+ end
225
+
226
+ # Sum up a min/max value over rows or columns in the cells selected.
227
+ # Takes the min/max (per +aggregate+) of the result of sending +meth+ to
228
+ # each cell, grouped by +row_or_column+.
229
+ #
230
+ def aggregate_cell_values(row_or_column, meth, aggregate)
231
+ values = {}
232
+ each do |cell|
233
+ index = cell.send(row_or_column)
234
+ values[index] = [values[index], cell.send(meth)].compact.send(aggregate)
235
+ end
236
+ values.values.inject(0, &:+)
237
+ end
238
+
239
+ # Transforms +spec+, a column / row specification, into an object that
240
+ # can be compared against a row or column number using ===. Normalizes
241
+ # negative indices to be positive, given a total size of +total+. The
242
+ # first row/column is indicated by +first+; this value is considered row
243
+ # or column 0.
244
+ #
245
+ def transform_spec(spec, first, total)
246
+ case spec
247
+ when Range
248
+ transform_spec(spec.begin, first, total) ..
249
+ transform_spec(spec.end, first, total)
250
+ when Integer
251
+ spec < 0 ? (first + total + spec) : first + spec
252
+ when Enumerable
253
+ spec.map { |x| first + x }
254
+ else # pass through
255
+ raise "Don't understand spec #{spec.inspect}"
256
+ end
257
+ end
258
+ end
259
+ end
260
+ end