File: print.rb

package info (click to toggle)
ruby-gnome2 2.2.0-5
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 11,360 kB
  • ctags: 14,222
  • sloc: ansic: 85,875; ruby: 38,232; sh: 80; xml: 41; makefile: 22
file content (247 lines) | stat: -rw-r--r-- 7,150 bytes parent folder | download | duplicates (6)
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#!/usr/bin/env ruby
=begin
  print.rb - Gtk::Print* sample

  Copyright (C) 2007 Mathieu Blondel
  This program is licenced under the same licence as Ruby-GNOME2.

  $Id: print.rb,v 1.1 2007/08/05 15:41:31 mutoh Exp $
=end

require 'gtk3'

# Values returned by a Pango::Layout or set in a Pango::Layout
# are always multiple of Pango::SCALE. Those are convenience methods to
# deal with that.
class Pango::Layout
    def size_in_points
        self.size.collect { |v| v / Pango::SCALE }
    end

    def width_in_points
        self.size[0] / Pango::SCALE
    end

    def height_in_points
        self.size[1] / Pango::SCALE
    end

    def width_in_points=(width)
        self.width = width * Pango::SCALE
    end
end

class Print < Gtk::PrintOperation

    FONT = Pango::FontDescription.new("sans 12")
    FONT_SMALL = Pango::FontDescription.new("sans 8")

    FONT_SIZE = 12
    FONT_SMALL_SIZE = 8

    def initialize (parent_window, text)
        super()
        @parent_window = parent_window
        @text = text

        # with this option disabled, the origin is the the upper left corner
        # *taking into consideration margins* !
        self.use_full_page = false
        self.unit = Gtk::PaperSize::Unit::POINTS

        # set default paper size
        page_setup = Gtk::PageSetup.new
        paper_size = Gtk::PaperSize.new(Gtk::PaperSize.default)
        page_setup.paper_size_and_default_margins = paper_size
        self.default_page_setup = page_setup

        # show a progress bar
        self.show_progress = true        

        # You must choose between "paginate" and "begin-print".
        # "begin-print" is emitted only once and "paginate" is emitted
        # until the block returns true.
        # In both cases, you must set the number of pages at the end with
        # Gtk::PrintOperation#n_pages=
        signal_connect("begin-print") do |pop, context|
            puts "calls begin-print"
            cr = context.cairo_context
            paragraphs = @text.split("\n")
            layouts = []
            paragraphs.each do |para|
                layouts << create_layout(cr, para)
            end

            # distribute paragraph layouts among pages
            @page_layouts = []

            curr_height = 0
            n_pages = 0
            layouts.each do |layout|
                height = layout.height_in_points
                if curr_height + height > real_page_height
                    n_pages += 1
                    curr_height = 0
                end
                @page_layouts[n_pages] ||= []
                @page_layouts[n_pages] << layout
                curr_height += height
            end

            pop.n_pages = n_pages + 1
        end

        signal_connect("draw-page") do |pop, context, page_num|
            puts "calls draw-page %d" % page_num

            cr = context.cairo_context

            x, y = [0,0] # this means we start at the upper left margin  

            if @page_layouts[page_num]
                @page_layouts[page_num].each do |layout|
                    cr.move_to(x,y)
                    cr.show_pango_layout(layout)            
                    y += layout.height_in_points
                end
                total_pages = @page_layouts.length
            else
                total_pages = 1
            end
            
            # page_num starts at 0
            draw_footer(cr, page_num + 1, total_pages)
        end
    end

    def run_print_dialog
        res = run(Action::PRINT_DIALOG, @parent_window)
        case res
            when RESULT_ERROR
                puts "error"
            when RESULT_CANCEL
                puts "cancelled"
            when RESULT_APPLY
                puts "applied"
            when RESULT_IN_PROGRESS
                puts "in progress"
        end
    end

    def run_preview
        res = run(Action::PREVIEW, @parent_window)
    end

    private

    def page_height
        setup = self.default_page_setup
        # this takes margins into consideration, contrary to get_paper_height
        setup.get_page_height(Gtk::PaperSize::Unit::POINTS)
    end

    def page_width
        setup = self.default_page_setup
        width = setup.get_page_width(Gtk::PaperSize::Unit::POINTS)
    end

    def real_page_height
        page_height - footer_height
    end

    def footer_height
        5 * FONT_SMALL_SIZE
    end

    def create_layout(cr, text)
        layout = cr.create_pango_layout

        layout.width_in_points = page_width
        layout.font_description = FONT
        layout.wrap = Pango::Layout::WrapMode::CHAR
        layout.ellipsize = Pango::Layout::ELLIPSIZE_NONE
        layout.single_paragraph_mode = false

        layout.text = text

        layout
    end

    def draw_footer(cr, nth_page, total_page)        
        layout = cr.create_pango_layout
        layout.alignment = Pango::Layout::ALIGN_RIGHT
        layout.font_description = FONT_SMALL
        layout.text = "Page %d/%d" % [nth_page, total_page] + "\n" + \
            Time.now.strftime("Printed on %Y/%m/%d at %H:%M") + "\n" + \
                "Powered by Ruby-GNOME2!"
        width, height = layout.size_in_points
        x, y = [page_width, page_height]
        x -= width
        y -= height
        cr.move_to(x, y)
        cr.show_pango_layout(layout)
        cr.rel_move_to(width, -2)
        cr.rel_line_to(-page_width, 0)
        cr.stroke
    end

end

class Window < Gtk::Window

    def initialize
        super

        signal_connect("delete-event") { Gtk.main_quit }

        set_default_size(600, 600)

        @textview = Gtk::TextView.new
        @textview.wrap_mode = Gtk::TextTag::WrapMode::WORD

        hbox = Gtk::Box.new(:horizontal)

        page_setup_button = Gtk::Button.new
        page_setup_button.label = "Page setup"
        page_setup_button.signal_connect("clicked") do
            @page_setup = Print::run_page_setup_dialog(self, # parent window
                                                       @page_setup)
        end

        print_preview_button = Gtk::Button.new(:stock_id => Gtk::Stock::PRINT_PREVIEW)
        print_preview_button.signal_connect("clicked") do
            printop = Print.new(self, @textview.buffer.text)
            printop.default_page_setup = @page_setup if @page_setup
            printop.run_preview
        end

        print_button = Gtk::Button.new(:stock_id => Gtk::Stock::PRINT)
        print_button.signal_connect("clicked") do
            printop = Print.new(self, @textview.buffer.text)
            printop.default_page_setup = @page_setup if @page_setup
            printop.run_print_dialog
        end

        [page_setup_button, print_preview_button, print_button].each do |b|
            hbox.pack_start(b, true, true)  # expand, fill
        end

        scrollbar = Gtk::Scrollbar.new(:vertical)

        vbox = Gtk::Box.new(:vertical)
        scroll = Gtk::ScrolledWindow.new.add(@textview)        
        scroll.set_policy(:automatic, :automatic)
        vbox.pack_start(scroll)
        vbox.pack_end(hbox, false, false)

        add(vbox)

        show_all
        
    end

end

Window.new

Gtk.main