#--
# PDF::Writer for Ruby.
# http://rubyforge.org/projects/ruby-pdf/
# Copyright 2003 - 2005 Austin Ziegler.
#
# Licensed under a MIT-style licence. See LICENCE in the main distribution
# for full licensing information.
#
# $Id: quickref.rb 186 2007-12-10 22:58:48Z sandal $
#++
require 'pdf/simpletable'
# = QuickRef
# A formatting language to create a quick reference sheet. This is a
# multi-column page in landscape mode that generally has three or four
# columns. This format may also be used for brochures, but brochure
# creation requires a bit of management to create properly.
#
# == Reference Sheets
# A three-column reference sheet is generally in the form of:
#
# Page 1:
# column 1 | column 2 | column 3
# Page 2:
# column 4 | column 5 | column 6
#
# The formatting language provided in QuickRef is based around this text
# flow. The title of the quick reference sheet is in column 1. The two
# pages are intended to be printed on both sides of pieces of paper so
# that columns 1 and 6 are matched. This will use a Z-fold that places
# columns 5 and 6 face to face and columns 2 and 3 face to face. In the
# folded reference sheet, columns 1 and 4 will be facing out.
#
# == Brochures
# In contrast, brochures differ vastly in their design, although the
# common brochure is also three columns and either follows the same layout
# as a reference sheet or uses an overlapping fold.
#
# When an overlapping fold is used, the title is typically on column 6
# (assuming a left-to-right reading order). A short summary will appear on
# column 4. Contact information about the maker of the brochure is
# typically in column 5. Columns 1, 2, and 3 will contain the main body of
# the brochure. The brochure will be folded so that columns 2 and 3 are
# face to face. After this, column 1 will face column 4 (exposed by the
# first fold). In the folded brochure, columns 5 and 6 are facing out.
#
# == Usage
# qr = PDF::QuickRef.new # 3-column LETTER
# qr.title "My QuickRef"
# qr.h1 "H1 Text"
# qr.lines "Text to put after the header."
# qr.save_as "MyQuickRef.pdf"
class PDF::QuickRef
# Create the quick reference document. +paper+ is passed unchanged to
# the PDF::Writer.new; the page is always created landscape. Margins
# are initialized to 18 points. After some additional initialization is
# performed, the quick reference document is yielded to an optional
# block for further configuration. All of this is done before the
# columns are started.
#
# After the columns are started, lines will be drawn between column
# positions.
def initialize(paper = "LETTER", columns = 3, column_separators_visible = true)
@pdf = PDF::Writer.new(:paper => paper, :orientation => :landscape)
@pdf.margins_pt 18
@pdf.y = @pdf.absolute_top_margin
@title_font = "Times-Roman"
@heading_font = "Times-Roman"
@body_font = "Times-Roman"
@code_font = "Courier"
@title_font_size = 14
@h1_font_size = 11
@h2_font_size = 9
@h3_font_size = 8
@h4_font_size = 7
@body_font_size = 6
@ptab = PDF::SimpleTable.new do |tab|
tab.column_order.replace %w(one two)
tab.font_size = @body_font_size
tab.show_lines = :none
tab.show_headings = false
tab.orientation = :center
tab.position = :center
end
@ltab = PDF::SimpleTable.new do |tab|
tab.column_order.replace %w(line)
tab.font_size = @body_font_size
tab.show_lines = :none
tab.show_headings = false
tab.orientation = :center
tab.position = :center
end
yield self if block_given?
@pdf.start_columns columns
@ptab.font_size = @body_font_size
@ltab.font_size = @body_font_size
@ptab.maximum_width = @pdf.column_width - 10
@ltab.maximum_width = @pdf.column_width - 10
if column_separators_visible
# Put lines between the columns.
all = @pdf.open_object
@pdf.save_state
@pdf.stroke_color! Color::RGB::Black
@pdf.stroke_style PDF::Writer::StrokeStyle::DEFAULT
(1 .. (columns - 1)).each do |ii|
x = @pdf.left_margin + (@pdf.column_width * ii)
x += (@pdf.column_gutter * (ii - 0.5))
@pdf.line(x, @pdf.page_height - @pdf.top_margin, x, @pdf.bottom_margin)
@pdf.stroke
end
@pdf.restore_state
@pdf.close_object
@pdf.add_object(all, :all_pages)
end
end
# Access to the raw PDF canvas for normal PDF::Writer configuration.
attr_reader :pdf
# The name of the font that will be used for #title text. The default
# font is Times-Roman.
attr_accessor :title_font
# The font encoding for #title text.
attr_accessor :title_font_encoding
# The size #title text. The default is 14 points.
attr_accessor :title_font_size
# The name of the font that will be used for #h1, #h2, #h3, and #h4
# text. The default is Times-Roman.
attr_accessor :heading_font
# The font encoding for #h1, #h2, #h3, and #h4 text.
attr_accessor :heading_font_encoding
# The size #h1 text. The default is 11 points.
attr_accessor :h1_font_size
# The size #h2 text. The default is 9 points.
attr_accessor :h2_font_size
# The size #h3 text. The default is 8 points.
attr_accessor :h3_font_size
# The size #h4 text. The default is 7 points.
attr_accessor :h4_font_size
# The name of the font that will be used for #body, #lines, and #pairs
# text. The default is 'Times-Roman'.
attr_accessor :body_font
# The font encoding for #body, #lines, and #pairs text.
attr_accessor :body_font_encoding
# The name of the font that will be used for #code, #codelines, and
# #codepairs text; this is generally a fixed-pitch font. The default is
# 'Courier'.
attr_accessor :code_font
# The font encoding for #code, #codelines, and #codepairs text.
attr_accessor :code_font_encoding
# The size #body and #code text. The default is 7 points.
attr_accessor :body_font_size
# Creates a two-column zebra-striped table using the #body font. Each
# line of the text is a separate row; the two columns are separated by
# tab characters.
def pairs(text)
data = text.split($/).map do |line|
one, two = line.split(/\t/)
{ 'one' => one, 'two' => two }
end
@ptab.data.replace data
@ptab.render_on(@pdf)
@pdf.text "\n", :font_size => @body_font_size
end
# Creates a two-column zebra-striped table using the #code font. Each
# line of the text is a separate row; the two columns are separated by
# tab characters.
def codepairs(text)
data = text.split($/).map do |line|
one, two = line.split(/\t/)
{ 'one' => one, 'two' => two }
end
@ptab.data.replace data
use_code_font
@ptab.render_on(@pdf)
use_body_font
@pdf.text "\n", :font_size => @body_font_size
end
# Creates a one-column zebra-striped table using the #body font. Each
# line of the text is a separate row.
def lines(text)
data = text.split($/).map { |line| { "line" => line } }
@ltab.data.replace data
@ltab.render_on(@pdf)
@pdf.text "\n", :font_size => @body_font_size
end
# Creates a one-column zebra-striped table using the #code font. Each
# line of the text is a separate row.
def codelines(text)
data = text.split($/).map { |line| { "line" => line } }
@ltab.data.replace data
use_code_font
@ltab.render_on(@pdf)
use_body_font
@pdf.text "\n", :font_size => @body_font_size
end
# Change the current font to the #title font.
def use_title_font
@pdf.select_font @title_font, @title_font_encoding
end
# Change the current font to the heading font (used normally by #h1,
# #h2, #h3, and #h4|).
def use_heading_font
@pdf.select_font @heading_font, @heading_font_encoding
end
# Change the current font to the #body font.
def use_body_font
@pdf.select_font @body_font, @body_font_encoding
end
# Change the current font to the #code font.
def use_code_font
@pdf.select_font @code_font, @code_font_encoding
end
# Writes the +text+ with the #title_font and #title_font_size centered
# in the column. After the title has been written, an #hline will be
# drawn under the title. The font is set to #body_font after the title
# is drawn.
def title(text)
use_title_font
@pdf.text text, :font_size => @title_font_size, :justification => :center
use_body_font
hline
end
# Writes the +text+ with the #heading_font and #h1_font_size left
# justified in the column. The font is set to #body_font after the
# heading is drawn.
def h1(text)
use_heading_font
@pdf.text text, :font_size => @h1_font_size
use_body_font
end
# Writes the +text+ with the #heading_font and #h2_font_size left
# justified in the column. The font is set to #body_font after the
# heading is drawn.
def h2(text)
use_heading_font
@pdf.text "#{text}", :font_size => @h2_font_size
use_body_font
end
# Writes the +text+ with the #heading_font and #h3_font_size left
# justified in the column. The font is set to #body_font after the
# heading is drawn.
def h3(text)
use_heading_font
@pdf.text "#{text}", :font_size => @h3_font_size
use_body_font
end
# Writes the +text+ with the #heading_font and #h4_font_size left
# justified in the column. The font is set to #body_font after the
# heading is drawn.
def h4(text)
use_heading_font
@pdf.text "#{text}", :font_size => @h4_font_size
use_body_font
end
# Writes body text. Paragraphs will be reflowed for optimal placement of
# text. Text separated by two line separators (e.g., \n\n, although the
# separator is platform dependent). The text will be placed with full
# justification.
def body(text)
# Transform the text a little.
paras = text.split(%r(#{$/}{2}))
paras.map! { |para| para.split($/).join(" ").squeeze(" ") }
text = paras.join("\n\n")
@pdf.text "#{text}\n", :font_size => @body_font_size, :justification => :full
end
# Writes code text. Newlines and spaces will be preserved.
def pre(text)
use_code_font
@pdf.text "#{text}\n", :font_size => @body_font_size
use_body_font
end
# Draws a horizontal line with the specified style and colour.
def hline(style = PDF::Writer::StrokeStyle::DEFAULT,
color = Color::RGB::Black)
@pdf.y -= 2.5
@pdf.save_state
@pdf.stroke_style style
@pdf.stroke_color! color
x0 = @pdf.left_margin
x1 = @pdf.left_margin + pdf.column_width
@pdf.line(x0, @pdf.y, x1, @pdf.y)
@pdf.stroke
@pdf.restore_state
@pdf.y -= 2.5
end
# Writes the Quick Reference to disk.
def save_as(filename)
@pdf.save_as(filename)
end
# Generates the PDF document as a string.
def render
@pdf.render
end
alias to_s render
# Creates a QuickRef document and then calls #instance_eval on the
# document. This allows for a more natural use of the QuickRef class as
# a DSL for creating these documents.
#
# === Using #make
# PDF::QuickRef.make do # 3-column LETTER
# title "My QuickRef"
# h1 "H1 Text"
# lines "Text to put after the header."
# save_as "MyQuickRef.pdf"
# end
def self.make(*args, &block)
qr = PDF::QuickRef.new(*args)
qr.__send__(:instance_eval, &block)
end
end