class Prawn::Text::Box

Generally, one would use the text_box convenience method. However, using Text::Box.new in conjunction with render() enables one to do look-ahead calculations prior to placing text on the page, or to determine how much vertical space was consumed by the printed text

Constants

VALID_OPTIONS

Attributes

ascender[R]

The height of the ascender of the last line printed

at[R]

The upper left corner of the text box

descender[R]

The height of the descender of the last line printed

leading[R]

The leading used during printing

line_height[R]

The line height of the last line printed

text[R]

The text that was successfully printed (or, if dry_run was used, the test that would have been successfully printed)

Public Class Methods

new(string, options={}) click to toggle source

See Prawn::Text#text_box for valid options

# File lib/prawn/text/box.rb, line 128
def initialize(string, options={})
  @inked          = false
  Prawn.verify_options(VALID_OPTIONS, options)
  options          = options.dup
  @overflow        = options[:overflow] || :truncate
  @original_string = string
  @text            = nil
  
  @document        = options[:document]
  @at              = options[:at] ||
                     [@document.bounds.left, @document.bounds.top]
  @width           = options[:width] ||
                     @document.bounds.right - @at[0]
  @height          = options[:height] ||
                     @at[1] - @document.bounds.bottom
  @align           = options[:align] || :left
  @vertical_align  = options[:valign] || :top
  @leading         = options[:leading] || 0
  @rotate          = options[:rotate] || 0
  @rotate_around   = options[:rotate_around] || :upper_left
  @single_line     = options[:single_line]
  @skip_encoding   = options[:skip_encoding] || @document.skip_encoding

  if @overflow == :expand
    # if set to expand, then we simply set the bottom
    # as the bottom of the document bounds, since that
    # is the maximum we should expand to
    @height = @at[1] - @document.bounds.bottom
    @overflow = :truncate
  end
  @min_font_size  = options[:min_font_size] || 5
  @line_wrap    = options [:line_wrap] || @document.default_line_wrap
  @options = @document.text_options.merge(:kerning => options[:kerning],
                                          :size    => options[:size],
                                          :style   => options[:style])
end

Public Instance Methods

height() click to toggle source

The height actually used during the previous render

# File lib/prawn/text/box.rb, line 203
def height
  return 0 if @baseline_y.nil? || @descender.nil?
  # baseline is already pushed down one line below the current
  # line, so we need to subtract line line_height and leading,
  # but we need to add in the descender since baseline is
  # above the descender
  @baseline_y.abs + @descender - @line_height - @leading
end
render(flags={}) click to toggle source

Render text to the document based on the settings defined in initialize.

In order to facilitate look-ahead calculations, render accepts a :dry_run => true option. If provided then everything is executed as if rendering, with the exception that nothing is drawn on the page. Useful for look-ahead computations of height, unprinted text, etc.

Returns any text that did not print under the current settings

# File lib/prawn/text/box.rb, line 175
def render(flags={})
  # dup because normalize_encoding changes the string
  string = @original_string.dup
  unprinted_text = ''
  @document.save_font do
    process_options

    unless @skip_encoding
      @document.font.normalize_encoding!(string)
    end

    @document.font_size(@font_size) do
      shrink_to_fit(string) if @overflow == :shrink_to_fit
      process_vertical_alignment(string)
      @inked = true unless flags[:dry_run]
      if @rotate != 0 && @inked
        unprinted_text = render_rotated(string)
      else
        unprinted_text = _render(string)
      end
      @inked = false
    end
  end
  unprinted_text
end

Private Instance Methods

_render(remaining_text) click to toggle source
# File lib/prawn/text/box.rb, line 271
def _render(remaining_text)
  @line_height = @document.font.height
  @descender   = @document.font.descender
  @ascender    = @document.font.ascender
  @baseline_y  = -@ascender
  
  printed_text = []
  
  while remaining_text &&
        remaining_text.length > 0 &&
        @baseline_y.abs + @descender <= @height
    line_to_print = @line_wrap.wrap_line(remaining_text.first_line,
                                           :document => @document,
                                           :kerning => @kerning,
                                           :size => @font_size,
                                           :width => @width)

    if line_to_print.empty? && remaining_text.length > 0
      raise Errors::CannotFit
    end

    remaining_text = remaining_text.slice(line_to_print.length..
                                          remaining_text.length)
    print_ellipses = (@overflow == :ellipses && last_line? &&
                      remaining_text.length > 0)
    printed_text << print_line(line_to_print, print_ellipses)
    @baseline_y -= (@line_height + @leading)
    break if @single_line
  end

  @text = printed_text.join("\n") if @inked
    
  remaining_text
end
insert_ellipses(line_to_print) click to toggle source
# File lib/prawn/text/box.rb, line 338
def insert_ellipses(line_to_print)
  if @document.width_of(line_to_print + "...",
                        :kerning => @kerning) < @width
    line_to_print.insert(-1, "...")
  else
    line_to_print[-3..-1] = "..." if line_to_print.length > 3
  end
end
last_line?() click to toggle source
# File lib/prawn/text/box.rb, line 334
def last_line?
  @baseline_y.abs + @descender > @height - @line_height
end
print_line(line_to_print, print_ellipses) click to toggle source
process_options() click to toggle source
# File lib/prawn/text/box.rb, line 236
def process_options
  # must be performed within a save_font bock because
  # document.process_text_options sets the font
  @document.process_text_options(@options)
  @font_size = @options[:size]
  @kerning   = @options[:kerning]
end
process_vertical_alignment(string) click to toggle source
# File lib/prawn/text/box.rb, line 214
def process_vertical_alignment(string)
  return if @vertical_align == :top
  _render(string)
  case @vertical_align
  when :center
    @at[1] = @at[1] - (@height - height) * 0.5
  when :bottom
    @at[1] = @at[1] - (@height - height)
  end
  @height = height
end
render_rotated(string) click to toggle source
# File lib/prawn/text/box.rb, line 244
def render_rotated(string)
  unprinted_text = ''

  case @rotate_around
  when :center
    x = @at[0] + @width * 0.5
    y = @at[1] - @height * 0.5
  when :upper_right
    x = @at[0] + @width
    y = @at[1]
  when :lower_right
    x = @at[0] + @width
    y = @at[1] - @height
  when :lower_left
    x = @at[0]
    y = @at[1] - @height
  else
    x = @at[0]
    y = @at[1]
  end

  @document.rotate(@rotate, :origin => [x, y]) do
    unprinted_text = _render(string)
  end
  unprinted_text
end
shrink_to_fit(string) click to toggle source

Decrease the font size until the text fits or the min font size is reached

# File lib/prawn/text/box.rb, line 228
def shrink_to_fit(string)
  while (unprinted_text = _render(string)).length > 0 &&
      @font_size > @min_font_size
    @font_size -= 0.5
    @document.font_size = @font_size
  end
end