7491b3dd24ed82bb9247420174477f1347369362
[geeqie.git] / src / print.cc
1 /*
2  * Copyright (C) 2018 The Geeqie Team
3  *
4  * Author: Colin Clark
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "main.h"
22 #include "print.h"
23
24 #include "exif.h"
25 #include "filedata.h"
26 #include "image-load.h"
27 #include "osd.h"
28 #include "pixbuf-util.h"
29 #include "ui-misc.h"
30 #include "ui-fileops.h"
31
32 #define PRINT_SETTINGS "print_settings" // filename save printer settings
33 #define PAGE_SETUP "page_setup" // filename save page setup
34
35 /* padding between objects */
36 #define PRINT_TEXT_PADDING 3.0
37
38 /* method to use when scaling down image data */
39 #define PRINT_MAX_INTERP GDK_INTERP_BILINEAR
40
41 /* reverse order is important */
42 enum TextPosition {
43         FOOTER_2,
44         FOOTER_1,
45         HEADER_2,
46         HEADER_1
47 };
48
49 struct PrintWindow
50 {
51         GtkWidget *vbox;
52         GList *source_selection;
53
54         gint job_page;
55         GtkTextBuffer *page_text;
56         gchar *template_string;
57         GtkWidget *parent;
58         ImageLoader     *job_loader;
59
60         GList *print_pixbuf_queue;
61         gboolean job_render_finished;
62         GSList *image_group;
63         GSList *page_group;
64 };
65
66 static gint print_layout_page_count(PrintWindow *pw)
67 {
68         gint images;
69
70         images = g_list_length(pw->source_selection);
71
72         if (images < 1 ) return 0;
73
74         return images;
75 }
76
77 static gboolean print_job_render_image(PrintWindow *pw);
78
79 static void print_job_render_image_loader_done(ImageLoader *il, gpointer data)
80 {
81         auto pw = static_cast<PrintWindow *>(data);
82         GdkPixbuf *pixbuf;
83
84         pixbuf = image_loader_get_pixbuf(il);
85
86         g_object_ref(pixbuf);
87         pw->print_pixbuf_queue = g_list_append(pw->print_pixbuf_queue, pixbuf);
88
89         image_loader_free(pw->job_loader);
90         pw->job_loader = nullptr;
91
92         pw->job_page++;
93
94         if (!print_job_render_image(pw))
95                 {
96                 pw->job_render_finished = TRUE;
97                 }
98 }
99
100 static gboolean print_job_render_image(PrintWindow *pw)
101 {
102         FileData *fd = nullptr;
103
104         fd = static_cast<FileData *>(g_list_nth_data(pw->source_selection, pw->job_page));
105         if (!fd) return FALSE;
106
107         image_loader_free(pw->job_loader);
108         pw->job_loader = nullptr;
109
110         pw->job_loader = image_loader_new(fd);
111         g_signal_connect(G_OBJECT(pw->job_loader), "done",
112                                                 (GCallback)print_job_render_image_loader_done, pw);
113
114         if (!image_loader_start(pw->job_loader))
115                 {
116                 image_loader_free(pw->job_loader);
117                 pw->job_loader= nullptr;
118                 }
119
120         return TRUE;
121 }
122
123 static void print_set_font_cb(GtkWidget *widget, gpointer data)
124 {
125         gpointer option;
126
127         if (g_strcmp0(static_cast<const gchar *>(data), "Image text font") == 0)
128                 {
129                 option = options->printer.image_font;
130                 }
131         else
132                 {
133                 option = options->printer.page_font;
134                 }
135
136         GtkWidget *dialog;
137         char *font;
138         PangoFontDescription *font_desc;
139
140         dialog = gtk_font_chooser_dialog_new(static_cast<const gchar *>(data), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
141         gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), static_cast<const gchar *>(option));
142
143         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
144                 {
145                 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
146                 font = pango_font_description_to_string(font_desc);
147                 g_free(option);
148                 option = g_strdup(font);
149                 g_free(font);
150                 }
151
152         gtk_widget_destroy(dialog);
153 }
154
155 static gint set_toggle(GSList *list, TextPosition pos)
156 {
157         GtkToggleButton *current_sel;
158         GtkToggleButton *new_sel;
159         gint new_pos = - 1;
160
161         current_sel = static_cast<GtkToggleButton *>(g_slist_nth(list, pos)->data);
162         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(current_sel)))
163                 {
164                 new_pos = (pos - 1);
165                 if (new_pos < 0)
166                         {
167                         new_pos = HEADER_1;
168                         }
169                 new_sel = static_cast<GtkToggleButton *>(g_slist_nth(list, new_pos)->data);
170                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(new_sel), TRUE);
171                 }
172         return new_pos;
173 }
174
175 static void image_text_position_h1_cb(GtkWidget *widget, gpointer data)
176 {
177         auto pw = static_cast<PrintWindow *>(data);
178         gint new_set;
179
180         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
181                 {
182                 new_set = set_toggle(pw->page_group, HEADER_1);
183                 if (new_set >= 0)
184                         {
185                         options->printer.page_text_position = new_set;
186                         }
187                 options->printer.image_text_position = HEADER_1;
188                 }
189 }
190
191 static void image_text_position_h2_cb(GtkWidget *widget, gpointer data)
192 {
193         auto pw = static_cast<PrintWindow *>(data);
194         gint new_set;
195
196         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
197                 {
198                 new_set = set_toggle(pw->page_group, HEADER_2);
199                 if (new_set >= 0)
200                         {
201                         options->printer.page_text_position = new_set;
202                         }
203                 options->printer.image_text_position = HEADER_2;
204                 }
205 }
206
207 static void image_text_position_f1_cb(GtkWidget *widget, gpointer data)
208 {
209         auto pw = static_cast<PrintWindow *>(data);
210         gint new_set;
211
212         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
213                 {
214                 new_set = set_toggle(pw->page_group, FOOTER_1);
215                 if (new_set >= 0)
216                         {
217                         options->printer.page_text_position = new_set;
218                         }
219                 options->printer.image_text_position = FOOTER_1;
220                 }
221 }
222
223 static void image_text_position_f2_cb(GtkWidget *widget, gpointer data)
224 {
225         auto pw = static_cast<PrintWindow *>(data);
226         gint new_set;
227
228         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
229                 {
230                 new_set = set_toggle(pw->page_group, FOOTER_2);
231                 if (new_set >= 0)
232                         {
233                         options->printer.page_text_position = new_set;
234                         }
235                 options->printer.image_text_position = FOOTER_2;
236                 }
237 }
238
239 static void page_text_position_h1_cb(GtkWidget *widget, gpointer data)
240 {
241         auto pw = static_cast<PrintWindow *>(data);
242         gint new_set;
243
244         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
245                 {
246                 new_set = set_toggle(pw->image_group, HEADER_1);
247                 if (new_set >= 0)
248                         {
249                         options->printer.image_text_position = new_set;
250                         }
251                 options->printer.page_text_position = HEADER_1;
252                 }
253 }
254
255 static void page_text_position_h2_cb(GtkWidget *widget, gpointer data)
256 {
257         auto pw = static_cast<PrintWindow *>(data);
258         gint new_set;
259
260         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
261                 {
262                 new_set = set_toggle(pw->image_group, HEADER_2);
263                 if (new_set >= 0)
264                         {
265                         options->printer.image_text_position = new_set;
266                         }
267                 options->printer.page_text_position = HEADER_2;
268                 }
269 }
270
271 static void page_text_position_f1_cb(GtkWidget *widget, gpointer data)
272 {
273         auto pw = static_cast<PrintWindow *>(data);
274         gint new_set;
275
276         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
277                 {
278                 new_set = set_toggle(pw->image_group, FOOTER_1);
279                 if (new_set >= 0)
280                         {
281                         options->printer.image_text_position = new_set;
282                         }
283                 options->printer.page_text_position = FOOTER_1;
284                 }
285 }
286
287 static void page_text_position_f2_cb(GtkWidget *widget, gpointer data)
288 {
289         auto pw = static_cast<PrintWindow *>(data);
290         gint new_set;
291
292         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
293                 {
294                 new_set = set_toggle(pw->image_group, FOOTER_2);
295                 if (new_set >= 0)
296                         {
297                         options->printer.image_text_position = new_set;
298                         }
299                 options->printer.page_text_position = FOOTER_2;
300                 }
301 }
302
303 static void set_print_image_text_string(gchar **template_string, const gchar *value)
304 {
305         g_assert(template_string);
306
307         g_free(*template_string);
308         *template_string = g_strdup(value);
309 }
310
311 static void image_text_template_view_changed_cb(GtkWidget *, gpointer data)
312 {
313         GtkWidget *pTextView;
314         GtkTextBuffer *pTextBuffer;
315         GtkTextIter iStart;
316         GtkTextIter iEnd;
317
318         pTextView = GTK_WIDGET(data);
319
320         pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
321         gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
322         gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
323
324         set_print_image_text_string(&options->printer.template_string,
325                                           gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
326 }
327
328 #define PRE_FORMATTED_COLUMNS 4
329 static void print_text_menu(GtkWidget *box, PrintWindow *pw)
330 {
331         GtkWidget *group;
332         GtkWidget *hbox;
333         GtkWidget *button;
334         GtkWidget *button1;
335         GtkWidget *button2;
336         GtkWidget *image_text_button;
337         GtkWidget *page_text_button;
338         GtkWidget *subgroup;
339         GtkWidget *page_text_view;
340         GtkWidget *image_text_template_view;
341         GtkWidget *scrolled;
342         GtkWidget *scrolled_pre_formatted;
343         GtkTextBuffer *buffer;
344
345         group = pref_group_new(box, FALSE, _("Image text"), GTK_ORIENTATION_VERTICAL);
346
347         image_text_button = pref_checkbox_new_int(group, _("Show image text"),
348                                                                                 options->printer.show_image_text, &options->printer.show_image_text);
349
350         subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
351
352         pref_checkbox_link_sensitivity(image_text_button, subgroup);
353
354         hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
355         gtk_box_pack_start(GTK_BOX(subgroup), hbox, FALSE, FALSE, 0);
356
357         /* order is important */
358         button1 = pref_radiobutton_new(hbox, nullptr,  "Header 1",
359                                                         options->printer.image_text_position == HEADER_1,
360                                                         G_CALLBACK(image_text_position_h1_cb), pw);
361         button1 = pref_radiobutton_new(hbox, button1,  "Header 2",
362                                                         options->printer.image_text_position == HEADER_2,
363                                                         G_CALLBACK(image_text_position_h2_cb), pw);
364         button1 = pref_radiobutton_new(hbox, button1, "Footer 1",
365                                                         options->printer.image_text_position == FOOTER_1,
366                                                         G_CALLBACK(image_text_position_f1_cb), pw);
367         button1 = pref_radiobutton_new(hbox, button1, "Footer 2",
368                                                         options->printer.image_text_position == FOOTER_2,
369                                                         G_CALLBACK(image_text_position_f2_cb), pw);
370         gtk_widget_show(hbox);
371         pw->image_group = (gtk_radio_button_get_group(GTK_RADIO_BUTTON(button1)));
372
373         image_text_template_view = gtk_text_view_new();
374
375         scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_text_template_view);
376         gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
377         gtk_widget_show(scrolled_pre_formatted);
378         gtk_widget_show(subgroup);
379
380         gtk_widget_set_tooltip_markup(image_text_template_view,
381                                         _("Extensive formatting options are shown in the Help file"));
382
383         scrolled = gtk_scrolled_window_new(nullptr, nullptr);
384         gtk_widget_set_size_request(scrolled, 200, 50);
385         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
386         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
387                                                                         GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
388         gtk_box_pack_start(GTK_BOX(subgroup), scrolled, TRUE, TRUE, 5);
389         gtk_widget_show(scrolled);
390
391         gtk_container_add(GTK_CONTAINER(scrolled), image_text_template_view);
392         gtk_widget_show(image_text_template_view);
393
394         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_text_template_view));
395         if (options->printer.template_string) gtk_text_buffer_set_text(buffer, options->printer.template_string, -1);
396         g_signal_connect(G_OBJECT(buffer), "changed",
397                          G_CALLBACK(image_text_template_view_changed_cb), image_text_template_view);
398
399         hbox = pref_box_new(subgroup, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
400
401         button = pref_button_new(nullptr, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
402                                  G_CALLBACK(print_set_font_cb), const_cast<char *>("Image text font"));
403
404         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
405         gtk_widget_show(button);
406
407         pref_spacer(group, PREF_PAD_GAP);
408
409         group = pref_group_new(box, FALSE, _("Page text"), GTK_ORIENTATION_VERTICAL);
410
411         page_text_button = pref_checkbox_new_int(group, _("Show page text"),
412                                           options->printer.show_page_text, &options->printer.show_page_text);
413
414         subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
415         pref_checkbox_link_sensitivity(page_text_button, subgroup);
416
417         hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
418         gtk_box_pack_start(GTK_BOX(subgroup), hbox, FALSE, FALSE, 0);
419
420         /* order is important */
421         button2 = pref_radiobutton_new(hbox, nullptr, "Header 1",
422                                                         options->printer.page_text_position == HEADER_1,
423                                                         G_CALLBACK(page_text_position_h1_cb), pw);
424         button2 = pref_radiobutton_new(hbox, button2,  "Header 2",
425                                                         options->printer.page_text_position == HEADER_2,
426                                                         G_CALLBACK(page_text_position_h2_cb), pw);
427         button2 = pref_radiobutton_new(hbox, button2, "Footer 1",
428                                                         options->printer.page_text_position == FOOTER_1,
429                                                         G_CALLBACK(page_text_position_f1_cb), pw);
430         button2 = pref_radiobutton_new(hbox, button2, "Footer 2",
431                                                         options->printer.page_text_position == FOOTER_2,
432                                                         G_CALLBACK(page_text_position_f2_cb), pw);
433         gtk_widget_show(hbox);
434         pw->page_group = (gtk_radio_button_get_group(GTK_RADIO_BUTTON(button2)));
435
436         scrolled = gtk_scrolled_window_new(nullptr, nullptr);
437         gtk_widget_set_size_request(scrolled, 50, 50);
438         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
439         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
440                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
441         gtk_box_pack_start(GTK_BOX(subgroup), scrolled, TRUE, TRUE, 5);
442         gtk_widget_show(scrolled);
443
444         page_text_view = gtk_text_view_new();
445         pw->page_text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page_text_view ));
446         gtk_text_buffer_set_text(GTK_TEXT_BUFFER(pw->page_text), options->printer.page_text, -1);
447         g_object_ref(pw->page_text);
448
449         gtk_widget_set_tooltip_markup(page_text_view, (_("Text shown on each page of a single or multi-page print job")));
450         gtk_container_add(GTK_CONTAINER(scrolled), page_text_view);
451         gtk_widget_show(page_text_view);
452
453         hbox = pref_box_new(subgroup, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
454
455         button = pref_button_new(nullptr, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
456                                  G_CALLBACK(print_set_font_cb), const_cast<char *>("Page text font"));
457
458         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
459         gtk_widget_show(button);
460 }
461
462 static gboolean paginate_cb(GtkPrintOperation *, GtkPrintContext *, gpointer data)
463 {
464         auto pw = static_cast<PrintWindow *>(data);
465
466         if (pw->job_render_finished)
467                 {
468                 return TRUE;
469                 }
470         else
471                 {
472                 return FALSE;
473                 }
474 }
475
476 gchar *form_image_text(const gchar *template_string, FileData *fd, PrintWindow *pw, gint page_nr, gint total)
477 {
478         const gchar *name;
479         gchar *text = nullptr;
480         GHashTable *vars;
481         gchar *window_title;
482         gchar *delimiter;
483         gchar *collection_name;
484
485         if (!fd) return nullptr;
486
487         name = fd->name;
488
489         vars = g_hash_table_new_full(g_str_hash, g_str_equal, nullptr, g_free);
490
491         window_title = g_strdup(gtk_window_get_title(GTK_WINDOW(pw->parent)));
492         delimiter = g_strstr_len(window_title, -1, " - Collection - ");
493         if (delimiter)
494                 {
495                 collection_name = g_strndup(window_title, delimiter - window_title);
496                 }
497         else
498                 {
499                 collection_name = nullptr;
500                 }
501         g_free(window_title);
502
503         if (collection_name)
504                 {
505                 osd_template_insert(vars, "collection", collection_name, OSDT_NONE);
506                 }
507
508         osd_template_insert(vars, "number", g_strdup_printf("%d", page_nr + 1), OSDT_NO_DUP);
509         osd_template_insert(vars, "total", g_strdup_printf("%d", total), OSDT_NO_DUP);
510         osd_template_insert(vars, "name", const_cast<gchar *>(name), OSDT_NONE);
511         osd_template_insert(vars, "date", fd ? (const_cast<gchar *>(text_from_time(fd->date))) : "", OSDT_NONE);
512         osd_template_insert(vars, "size", fd ? (text_from_size_abrev(fd->size)) : g_strdup(""), OSDT_FREE);
513
514         if (fd->pixbuf)
515                 {
516                 gint w, h;
517                 w = gdk_pixbuf_get_width(fd->pixbuf);
518                 h = gdk_pixbuf_get_height(fd->pixbuf);
519
520                 osd_template_insert(vars, "width", g_strdup_printf("%d", w), OSDT_NO_DUP);
521                 osd_template_insert(vars, "height", g_strdup_printf("%d", h), OSDT_NO_DUP);
522                 osd_template_insert(vars, "res", g_strdup_printf("%d Ã— %d", w, h), OSDT_FREE);
523                 }
524         else
525                 {
526                 osd_template_insert(vars, "width", nullptr, OSDT_NONE);
527                 osd_template_insert(vars, "height", nullptr, OSDT_NONE);
528                 osd_template_insert(vars, "res", nullptr, OSDT_NONE);
529                 }
530
531         text = image_osd_mkinfo(template_string, fd, vars);
532         g_hash_table_destroy(vars);
533
534         g_free(collection_name);
535
536         return text;
537 }
538
539 static void draw_page(GtkPrintOperation *, GtkPrintContext *context, gint page_nr, gpointer data)
540 {
541         auto pw = static_cast<PrintWindow *>(data);
542         FileData *fd;
543         cairo_t *cr;
544         gdouble context_width, context_height;
545         gdouble pixbuf_image_width, pixbuf_image_height;
546         gdouble width_offset;
547         gdouble height_offset;
548         GdkPixbuf *pixbuf;
549         GdkPixbuf *rotated = nullptr;
550         PangoLayout *layout_image = nullptr;
551         PangoLayout *layout_page = nullptr;
552         PangoFontDescription *desc;
553         GString *image_text = g_string_new(nullptr);
554         GString *page_text = g_string_new(nullptr);
555         PangoRectangle ink_rect, logical_rect;
556         gdouble w, h, scale;
557         gdouble image_text_width, image_text_height, page_text_width, page_text_height;
558         gint image_y;
559         gint incr_y;
560         gdouble pango_height;
561         gdouble pango_image_height;
562         gdouble pango_page_height;
563         GtkTextIter start, end;
564         gchar *tmp;
565         gint total;
566
567         fd = static_cast<FileData *>(g_list_nth_data(pw->source_selection, page_nr));
568         total = g_list_length(pw->source_selection);
569
570         pixbuf = static_cast<GdkPixbuf *>(g_list_nth_data(pw->print_pixbuf_queue, page_nr));
571         if (fd->exif_orientation != EXIF_ORIENTATION_TOP_LEFT)
572                 {
573                 rotated = pixbuf_apply_orientation(pixbuf, fd->exif_orientation);
574                 pixbuf = rotated;
575                 }
576
577         pixbuf_image_width = gdk_pixbuf_get_width(pixbuf);
578         pixbuf_image_height = gdk_pixbuf_get_height(pixbuf);
579
580         if (options->printer.show_image_text)
581                 {
582                 image_text = g_string_append(image_text, form_image_text(options->printer.template_string, fd, pw, page_nr, total));
583                 }
584
585         if (options->printer.show_page_text)
586                 {
587                 gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(pw->page_text), &start, &end);
588
589                 tmp = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(pw->page_text), &start, &end, FALSE);
590                 page_text = g_string_append(page_text, tmp);
591
592                 g_free(tmp);
593                 }
594
595         cr = gtk_print_context_get_cairo_context(context);
596         context_width = gtk_print_context_get_width(context);
597         context_height = gtk_print_context_get_height(context);
598
599         pango_image_height = 0;
600         pango_page_height = 0;
601         image_text_width = 0;
602         page_text_width = 0;
603
604         if (image_text->len > 0)
605                 {
606                 layout_image = pango_cairo_create_layout(cr);
607
608                 pango_layout_set_text(layout_image, image_text->str, -1);
609                 desc = pango_font_description_from_string(options->printer.image_font);
610                 pango_layout_set_font_description(layout_image, desc);
611
612                 pango_layout_get_extents(layout_image, &ink_rect, &logical_rect);
613                 image_text_width = (static_cast<gdouble>(logical_rect.width) / PANGO_SCALE) ;
614                 image_text_height = (static_cast<gdouble>(logical_rect.height) / PANGO_SCALE);
615
616                 pango_layout_set_alignment(layout_image, PANGO_ALIGN_CENTER);
617                 pango_layout_set_text(layout_image, image_text->str, -1);
618
619                 pango_image_height = image_text_height + PRINT_TEXT_PADDING * 2;
620
621                 pango_font_description_free(desc);
622                 }
623
624         if (page_text->len > 0)
625                 {
626                 layout_page = pango_cairo_create_layout(cr);
627
628                 pango_layout_set_text(layout_page, page_text->str, -1);
629                 desc = pango_font_description_from_string(options->printer.page_font);
630                 pango_layout_set_font_description(layout_page, desc);
631
632                 pango_layout_get_extents(layout_page, &ink_rect, &logical_rect);
633                 page_text_width = (static_cast<gdouble>(logical_rect.width) / PANGO_SCALE) ;
634                 page_text_height = (static_cast<gdouble>(logical_rect.height) / PANGO_SCALE);
635
636                 pango_layout_set_alignment(layout_page, PANGO_ALIGN_CENTER);
637                 pango_layout_set_text(layout_page, page_text->str, -1);
638
639                 pango_page_height = page_text_height + PRINT_TEXT_PADDING * 2;
640
641                 pango_font_description_free(desc);
642                 }
643
644         pango_height = pango_image_height + pango_page_height;
645
646         if ((context_width / pixbuf_image_width) < ((context_height - pango_height) / pixbuf_image_height))
647                 {
648                 w = context_width;
649                 scale = context_width / pixbuf_image_width;
650                 h = pixbuf_image_height * scale;
651                 height_offset = (context_height - (h + pango_height)) / 2;
652                 width_offset = 0;
653                 }
654         else
655                 {
656                 h = context_height - pango_height ;
657                 scale = (context_height - pango_height) / pixbuf_image_height;
658                 w = pixbuf_image_width * scale;
659                 height_offset = 0;
660                 width_offset = (context_width - (pixbuf_image_width * scale)) / 2;
661                 }
662
663         incr_y = height_offset;
664
665         if (options->printer.page_text_position == HEADER_1 && page_text->len > 0)
666                 {
667                 cairo_move_to(cr, (w / 2) - (page_text_width / 2) + width_offset, incr_y);
668                 pango_cairo_show_layout(cr, layout_page);
669
670                 incr_y = incr_y + pango_page_height;
671                 }
672
673         if (options->printer.image_text_position == HEADER_1 && image_text->len > 0)
674                 {
675                 cairo_move_to(cr, (w / 2) - (image_text_width / 2) + width_offset, incr_y + PRINT_TEXT_PADDING);
676                 pango_cairo_show_layout(cr, layout_image);
677
678                 incr_y = incr_y + pango_image_height;
679                 }
680
681         if (options->printer.page_text_position == HEADER_2 && page_text->len > 0)
682                 {
683                 cairo_move_to(cr, (w / 2) - (page_text_width / 2) + width_offset, incr_y);
684                 pango_cairo_show_layout(cr, layout_page);
685
686                 incr_y = incr_y + pango_page_height;
687                 }
688
689         if (options->printer.image_text_position == HEADER_2 && image_text->len > 0)
690                 {
691                 cairo_move_to(cr, (w / 2) - (image_text_width / 2) + width_offset, incr_y);
692                 pango_cairo_show_layout(cr, layout_image);
693
694                 incr_y = incr_y + pango_image_height;
695                 }
696
697         image_y = incr_y;
698         incr_y = incr_y + h;
699
700         if (options->printer.page_text_position == FOOTER_1 && page_text->len > 0)
701                 {
702                 cairo_move_to(cr, (w / 2) - (page_text_width / 2) + width_offset, incr_y + PRINT_TEXT_PADDING);
703                 pango_cairo_show_layout(cr, layout_page);
704
705                 incr_y = incr_y + pango_page_height;
706                 }
707
708         if (options->printer.image_text_position == FOOTER_1 && image_text->len > 0)
709                 {
710                 cairo_move_to(cr, (w / 2) - (image_text_width / 2) + width_offset, incr_y);
711                 pango_cairo_show_layout(cr, layout_image);
712
713                 incr_y = incr_y + pango_image_height;
714                 }
715
716         if (options->printer.page_text_position == FOOTER_2 && page_text->len > 0)
717                 {
718                 cairo_move_to(cr, (w / 2) - (page_text_width / 2) + width_offset, incr_y);
719                 pango_cairo_show_layout(cr, layout_page);
720
721                 incr_y = incr_y + pango_page_height;
722                 }
723
724         if (options->printer.image_text_position == FOOTER_2 && image_text->len > 0)
725                 {
726                 cairo_move_to(cr, (w / 2) - (image_text_width / 2) + width_offset, incr_y);
727                 pango_cairo_show_layout(cr, layout_image);
728                 }
729
730         cairo_scale(cr, scale, scale);
731
732         cairo_rectangle(cr,  width_offset * scale , image_y, pixbuf_image_width / scale, pixbuf_image_height / scale);
733         gdk_cairo_set_source_pixbuf(cr, pixbuf, width_offset / scale, image_y / scale);
734         cairo_fill(cr);
735
736         if (image_text->len > 0)
737                 {
738                 g_object_unref(layout_image);
739                 g_string_free(image_text, TRUE);
740                 }
741         if (page_text->len > 0)
742                 {
743                 g_object_unref(layout_page);
744                 g_string_free(page_text, TRUE);
745                 }
746
747         if (rotated) g_object_unref(rotated);
748 }
749
750 static void begin_print(GtkPrintOperation *operation, GtkPrintContext *, gpointer user_data)
751 {
752         auto pw = static_cast<PrintWindow *>(user_data);
753         gint page_count;
754
755         page_count = print_layout_page_count(pw);
756         gtk_print_operation_set_n_pages (operation, page_count);
757
758         print_job_render_image(pw);
759 }
760
761
762 GObject *option_tab_cb(GtkPrintOperation *, gpointer user_data)
763 {
764         auto pw = static_cast<PrintWindow *>(user_data);
765
766         return G_OBJECT(pw->vbox);
767 }
768
769 static void print_pref_store(PrintWindow *pw)
770 {
771         gchar *tmp;
772         GtkTextIter start, end;
773
774         gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(pw->page_text), &start, &end);
775         tmp = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(pw->page_text), &start, &end, FALSE);
776         g_free(options->printer.page_text);
777         options->printer.page_text = g_strdup(tmp);
778         g_free(tmp);
779 }
780
781 static void end_print_cb(GtkPrintOperation *operation, GtkPrintContext *, gpointer data)
782 {
783         auto pw = static_cast<PrintWindow *>(data);
784         GList *work;
785         GdkPixbuf *pixbuf;
786         gchar *path;
787         GtkPrintSettings *print_settings;
788         GtkPageSetup *page_setup;
789         GError *error = nullptr;
790
791         print_settings = gtk_print_operation_get_print_settings(operation);
792         path = g_build_filename(get_rc_dir(), PRINT_SETTINGS, NULL);
793
794         gtk_print_settings_to_file(print_settings, path, &error);
795         if (error)
796                 {
797                 log_printf("Error: Print settings save failed:\n%s", error->message);
798                 g_error_free(error);
799                 error = nullptr;
800                 }
801         g_free(path);
802         g_object_unref(print_settings);
803
804         page_setup = gtk_print_operation_get_default_page_setup(operation);
805         path = g_build_filename(get_rc_dir(), PAGE_SETUP, NULL);
806
807         gtk_page_setup_to_file(page_setup, path, &error);
808         if (error)
809                 {
810                 log_printf("Error: Print page setup save failed:\n%s", error->message);
811                 g_error_free(error);
812                 error = nullptr;
813                 }
814         g_free(path);
815         g_object_unref(page_setup);
816
817         print_pref_store(pw);
818
819         work = pw->print_pixbuf_queue;
820         while (work)
821                 {
822                 pixbuf = static_cast<GdkPixbuf *>(work->data);
823                 if (pixbuf)
824                         {
825                         g_object_unref(pixbuf);
826                         }
827                 work = work->next;
828                 }
829         g_list_free(pw->print_pixbuf_queue);
830         g_object_unref(pw->page_text);
831         g_free(pw);
832 }
833
834 void print_window_new(FileData *, GList *selection, GList *, GtkWidget *parent)
835 {
836         GtkWidget *vbox;
837         GtkPrintOperation *operation;
838         GtkPageSetup *page_setup;
839         gchar *uri;
840         const gchar *dir;
841         GError *error = nullptr;
842         gchar *path;
843         GtkPrintSettings *settings;
844
845         auto pw = g_new0(PrintWindow, 1);
846
847         pw->source_selection = file_data_process_groups_in_selection(selection, FALSE, nullptr);
848
849         if (print_layout_page_count(pw) == 0)
850                 {
851                 return;
852                 }
853
854         pw->parent = parent;
855
856         vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
857         gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
858         gtk_widget_show(vbox);
859
860         print_text_menu(vbox, pw);
861         pw->vbox = vbox;
862
863         pw->print_pixbuf_queue = nullptr;
864         pw->job_render_finished = FALSE;
865         pw->job_page = 0;
866
867         operation = gtk_print_operation_new();
868         settings = gtk_print_settings_new();
869
870         gtk_print_operation_set_custom_tab_label(operation, "Options");
871         gtk_print_operation_set_use_full_page(operation, TRUE);
872         gtk_print_operation_set_unit(operation, GTK_UNIT_POINTS);
873         gtk_print_operation_set_embed_page_setup(operation, TRUE);
874         gtk_print_operation_set_allow_async (operation, TRUE);
875         dir = g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS);
876         if (dir == nullptr)
877                 {
878                 dir = g_get_home_dir();
879                 }
880
881         uri = g_build_filename("file:/", dir, "geeqie-file.pdf", NULL);
882         gtk_print_settings_set(settings, GTK_PRINT_SETTINGS_OUTPUT_URI, uri);
883         g_free(uri);
884
885         path = g_build_filename(get_rc_dir(), PRINT_SETTINGS, NULL);
886         gtk_print_settings_load_file(settings, path, &error);
887         if (error)
888                 {
889                 log_printf("Error: Printer settings load failed:\n%s", error->message);
890                 g_error_free(error);
891                 error = nullptr;
892                 }
893         gtk_print_operation_set_print_settings(operation, settings);
894         g_free(path);
895
896         page_setup = gtk_page_setup_new();
897         path = g_build_filename(get_rc_dir(), PAGE_SETUP, NULL);
898         gtk_page_setup_load_file(page_setup, path, &error);
899         if (error)
900                 {
901                 log_printf("Error: Print page setup load failed:\n%s", error->message);
902                 g_error_free(error);
903                 error = nullptr;
904                 }
905         gtk_print_operation_set_default_page_setup(operation, page_setup);
906         g_free(path);
907
908         g_signal_connect (G_OBJECT (operation), "begin-print",
909                                         G_CALLBACK (begin_print), pw);
910         g_signal_connect (G_OBJECT (operation), "draw-page",
911                                         G_CALLBACK (draw_page), pw);
912         g_signal_connect (G_OBJECT (operation), "end-print",
913                                         G_CALLBACK (end_print_cb), pw);
914         g_signal_connect (G_OBJECT (operation), "create-custom-widget",
915                                         G_CALLBACK (option_tab_cb), pw);
916         g_signal_connect (G_OBJECT (operation), "paginate",
917                                         G_CALLBACK (paginate_cb), pw);
918
919         gtk_print_operation_set_n_pages(operation, print_layout_page_count(pw));
920
921         gtk_print_operation_run(operation, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
922                                                                                                 GTK_WINDOW (parent), &error);
923
924         if (error)
925                 {
926                 GtkWidget *dialog;
927
928                 dialog = gtk_message_dialog_new(GTK_WINDOW (parent),
929                                                                 GTK_DIALOG_DESTROY_WITH_PARENT,
930                                                                 GTK_MESSAGE_ERROR,
931                                                                 GTK_BUTTONS_CLOSE,
932                                                                 "%s", error->message);
933                 g_error_free (error);
934
935                 g_signal_connect(dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL);
936
937                 gtk_widget_show (dialog);
938                 }
939
940         g_object_unref(page_setup);
941         g_object_unref(settings);
942 }
943 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */