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