File: column_box.rb

package info (click to toggle)
ruby-prawn 2.3.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 4,380 kB
  • sloc: ruby: 15,820; sh: 43; makefile: 20
file content (142 lines) | stat: -rw-r--r-- 4,083 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# frozen_string_literal: true

# column_box.rb: Extends BoundingBox to allow for columns of text
#
# Author Paul Ostazeski.
#
# This is free software. Please see the LICENSE and COPYING files for details.

require_relative 'bounding_box'

module Prawn
  class Document
    # @group Experimental API

    # A column box is a bounding box with the additional property that when
    # text flows past the bottom, it will wrap first to another column on the
    # same page, and only flow to the next page when all the columns are
    # filled.
    #
    # column_box accepts the same parameters as bounding_box, as well as the
    # number of :columns and a :spacer (in points) between columns. If resetting
    # the top margin is desired on a new page (e.g. to allow for initial page
    # wide column titles) the option :reflow_margins => true can be set.
    #
    # Defaults are :columns = 3, :spacer = font_size, and
    # :reflow_margins => false
    #
    # Under PDF::Writer, "spacer" was known as "gutter"
    #
    def column_box(*args, &block)
      init_column_box(block) do |parent_box|
        map_to_absolute!(args[0])
        @bounding_box = ColumnBox.new(self, parent_box, *args)
      end
    end

    private

    def init_column_box(user_block, options = {})
      parent_box = @bounding_box

      yield(parent_box)

      self.y = @bounding_box.absolute_top
      user_block.call
      self.y = @bounding_box.absolute_bottom unless options[:hold_position]

      @bounding_box = parent_box
    end

    # Implements the necessary functionality to allow Document#column_box to
    # work.
    #
    class ColumnBox < BoundingBox
      def initialize(document, parent, point, options = {}) #:nodoc:
        super
        @columns = options[:columns] || 3
        @spacer = options[:spacer] || @document.font_size
        @current_column = 0
        @reflow_margins = options[:reflow_margins]
      end

      # The column width, not the width of the whole box,
      # before left and/or right padding
      def bare_column_width
        (@width - @spacer * (@columns - 1)) / @columns
      end

      # The column width after padding.
      # Used to calculate how long a line of text can be.
      #
      def width
        bare_column_width - (@total_left_padding + @total_right_padding)
      end

      # Column width including the spacer.
      #
      def width_of_column
        bare_column_width + @spacer
      end

      # x coordinate of the left edge of the current column
      #
      def left_side
        absolute_left + (width_of_column * @current_column)
      end

      # Relative position of the left edge of the current column
      #
      def left
        width_of_column * @current_column
      end

      # x co-orordinate of the right edge of the current column
      #
      def right_side
        columns_from_right = @columns - (1 + @current_column)
        absolute_right - (width_of_column * columns_from_right)
      end

      # Relative position of the right edge of the current column.
      #
      def right
        left + width
      end

      # Moves to the next column or starts a new page if currently positioned at
      # the rightmost column.
      def move_past_bottom
        @current_column = (@current_column + 1) % @columns
        @document.y = @y
        if @current_column.zero?
          if @reflow_margins
            @y = @parent.absolute_top
          end
          @document.start_new_page
        end
      end

      # Override the padding functions so as not to split the padding amount
      # between all columns on the page.

      def add_left_padding(left_padding)
        @total_left_padding += left_padding
        @x += left_padding
      end

      def subtract_left_padding(left_padding)
        @total_left_padding -= left_padding
        @x -= left_padding
      end

      def add_right_padding(right_padding)
        @total_right_padding += right_padding
      end

      def subtract_right_padding(right_padding)
        @total_right_padding -= right_padding
      end
    end
  end
end