Simplify vflist_get_formatted()
[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_BILINEAR
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 *rotated = NULL;
575         PangoLayout *layout_image = NULL;
576         PangoLayout *layout_page = NULL;
577         PangoFontDescription *desc;
578         GString *image_text = g_string_new(NULL);
579         GString *page_text = g_string_new(NULL);
580         PangoRectangle ink_rect, logical_rect;
581         gdouble w, h, scale;
582         gdouble image_text_width, image_text_height, page_text_width, page_text_height;
583         gint image_y;
584         gint incr_y;
585         gdouble pango_height;
586         gdouble pango_image_height;
587         gdouble pango_page_height;
588         GtkTextIter start, end;
589         gchar *tmp;
590         gint total;
591
592         fd = g_list_nth_data(pw->source_selection, page_nr);
593         total = g_list_length(pw->source_selection);
594
595         pixbuf = g_list_nth_data(pw->print_pixbuf_queue, page_nr);
596         if (fd->exif_orientation != EXIF_ORIENTATION_TOP_LEFT)
597                 {
598                 rotated = pixbuf_apply_orientation(pixbuf, fd->exif_orientation);
599                 pixbuf = rotated;
600                 }
601
602         pixbuf_image_width = gdk_pixbuf_get_width(pixbuf);
603         pixbuf_image_height = gdk_pixbuf_get_height(pixbuf);
604
605         if (options->printer.show_image_text)
606                 {
607                 image_text = g_string_append(image_text, form_image_text(options->printer.template_string, fd, pw, page_nr, total));
608                 }
609
610         if (options->printer.show_page_text)
611                 {
612                 gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(pw->page_text), &start, &end);
613
614                 tmp = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(pw->page_text), &start, &end, FALSE);
615                 page_text = g_string_append(page_text, tmp);
616
617                 g_free(tmp);
618                 }
619
620         cr = gtk_print_context_get_cairo_context(context);
621         context_width = gtk_print_context_get_width(context);
622         context_height = gtk_print_context_get_height(context);
623
624         pango_image_height = 0;
625         pango_page_height = 0;
626         image_text_width = 0;
627         page_text_width = 0;
628
629         if (image_text->len > 0)
630                 {
631                 layout_image = pango_cairo_create_layout(cr);
632
633                 pango_layout_set_text(layout_image, image_text->str, -1);
634                 desc = pango_font_description_from_string(options->printer.image_font);
635                 pango_layout_set_font_description(layout_image, desc);
636
637                 pango_layout_get_extents(layout_image, &ink_rect, &logical_rect);
638                 image_text_width = ((gdouble)logical_rect.width / PANGO_SCALE) ;
639                 image_text_height = ((gdouble)logical_rect.height / PANGO_SCALE);
640
641                 pango_layout_set_alignment(layout_image, PANGO_ALIGN_CENTER);
642                 pango_layout_set_text(layout_image, image_text->str, -1);
643
644                 pango_image_height = image_text_height + PRINT_TEXT_PADDING * 2;
645
646                 pango_font_description_free(desc);
647                 }
648
649         if (page_text->len > 0)
650                 {
651                 layout_page = pango_cairo_create_layout(cr);
652
653                 pango_layout_set_text(layout_page, page_text->str, -1);
654                 desc = pango_font_description_from_string(options->printer.page_font);
655                 pango_layout_set_font_description(layout_page, desc);
656
657                 pango_layout_get_extents(layout_page, &ink_rect, &logical_rect);
658                 page_text_width = ((gdouble)logical_rect.width / PANGO_SCALE) ;
659                 page_text_height = ((gdouble)logical_rect.height / PANGO_SCALE);
660
661                 pango_layout_set_alignment(layout_page, PANGO_ALIGN_CENTER);
662                 pango_layout_set_text(layout_page, page_text->str, -1);
663
664                 pango_page_height = page_text_height + PRINT_TEXT_PADDING * 2;
665
666                 pango_font_description_free(desc);
667                 }
668
669         pango_height = pango_image_height + pango_page_height;
670
671         if ((context_width / pixbuf_image_width) < ((context_height - pango_height) / pixbuf_image_height))
672                 {
673                 w = context_width;
674                 scale = context_width / pixbuf_image_width;
675                 h = pixbuf_image_height * scale;
676                 height_offset = (context_height - (h + pango_height)) / 2;
677                 width_offset = 0;
678                 }
679         else
680                 {
681                 h = context_height - pango_height ;
682                 scale = (context_height - pango_height) / pixbuf_image_height;
683                 w = pixbuf_image_width * scale;
684                 height_offset = 0;
685                 width_offset = (context_width - (pixbuf_image_width * scale)) / 2;
686                 }
687
688         incr_y = height_offset;
689
690         if (options->printer.page_text_position == HEADER_1 && page_text->len > 0)
691                 {
692                 cairo_move_to(cr, (w / 2) - (page_text_width / 2) + width_offset, incr_y);
693                 pango_cairo_show_layout(cr, layout_page);
694
695                 incr_y = incr_y + pango_page_height;
696                 }
697
698         if (options->printer.image_text_position == HEADER_1 && image_text->len > 0)
699                 {
700                 cairo_move_to(cr, (w / 2) - (image_text_width / 2) + width_offset, incr_y + PRINT_TEXT_PADDING);
701                 pango_cairo_show_layout(cr, layout_image);
702
703                 incr_y = incr_y + pango_image_height;
704                 }
705
706         if (options->printer.page_text_position == HEADER_2 && page_text->len > 0)
707                 {
708                 cairo_move_to(cr, (w / 2) - (page_text_width / 2) + width_offset, incr_y);
709                 pango_cairo_show_layout(cr, layout_page);
710
711                 incr_y = incr_y + pango_page_height;
712                 }
713
714         if (options->printer.image_text_position == HEADER_2 && image_text->len > 0)
715                 {
716                 cairo_move_to(cr, (w / 2) - (image_text_width / 2) + width_offset, incr_y);
717                 pango_cairo_show_layout(cr, layout_image);
718
719                 incr_y = incr_y + pango_image_height;
720                 }
721
722         image_y = incr_y;
723         incr_y = incr_y + h;
724
725         if (options->printer.page_text_position == FOOTER_1 && page_text->len > 0)
726                 {
727                 cairo_move_to(cr, (w / 2) - (page_text_width / 2) + width_offset, incr_y + PRINT_TEXT_PADDING);
728                 pango_cairo_show_layout(cr, layout_page);
729
730                 incr_y = incr_y + pango_page_height;
731                 }
732
733         if (options->printer.image_text_position == FOOTER_1 && image_text->len > 0)
734                 {
735                 cairo_move_to(cr, (w / 2) - (image_text_width / 2) + width_offset, incr_y);
736                 pango_cairo_show_layout(cr, layout_image);
737
738                 incr_y = incr_y + pango_image_height;
739                 }
740
741         if (options->printer.page_text_position == FOOTER_2 && page_text->len > 0)
742                 {
743                 cairo_move_to(cr, (w / 2) - (page_text_width / 2) + width_offset, incr_y);
744                 pango_cairo_show_layout(cr, layout_page);
745
746                 incr_y = incr_y + pango_page_height;
747                 }
748
749         if (options->printer.image_text_position == FOOTER_2 && image_text->len > 0)
750                 {
751                 cairo_move_to(cr, (w / 2) - (image_text_width / 2) + width_offset, incr_y);
752                 pango_cairo_show_layout(cr, layout_image);
753                 }
754
755         cairo_scale(cr, scale, scale);
756
757         cairo_rectangle(cr,  width_offset * scale , image_y, pixbuf_image_width / scale, pixbuf_image_height / scale);
758         gdk_cairo_set_source_pixbuf(cr, pixbuf, width_offset / scale, image_y / scale);
759         cairo_fill(cr);
760
761         if (image_text->len > 0)
762                 {
763                 g_object_unref(layout_image);
764                 g_string_free(image_text, TRUE);
765                 }
766         if (page_text->len > 0)
767                 {
768                 g_object_unref(layout_page);
769                 g_string_free(page_text, TRUE);
770                 }
771
772         if (rotated) g_object_unref(rotated);
773
774         return;
775 }
776
777 static void begin_print(GtkPrintOperation *operation,
778                                                 GtkPrintContext *context,
779                                                 gpointer user_data)
780 {
781         PrintWindow *pw = user_data;
782         gint page_count;
783
784         page_count = print_layout_page_count(pw);
785         gtk_print_operation_set_n_pages (operation, page_count);
786
787         print_job_render_image(pw);
788 }
789
790
791 GObject *option_tab_cb(GtkPrintOperation *operation, gpointer user_data)
792 {
793         PrintWindow *pw = user_data;
794
795         return G_OBJECT(pw->vbox);
796 }
797
798 static void print_pref_store(PrintWindow *pw)
799 {
800         gchar *tmp;
801         GtkTextIter start, end;
802
803         gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(pw->page_text), &start, &end);
804         tmp = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(pw->page_text), &start, &end, FALSE);
805         g_free(options->printer.page_text);
806         options->printer.page_text = g_strdup(tmp);
807         g_free(tmp);
808 }
809
810 static void end_print_cb(GtkPrintOperation *operation,
811                                                                 GtkPrintContext *context, gpointer data)
812 {
813         PrintWindow *pw = data;
814         GList *work;
815         GdkPixbuf *pixbuf;
816         gchar *path;
817         GtkPrintSettings *print_settings;
818         GtkPageSetup *page_setup;
819         GError *error = NULL;
820
821         print_settings = gtk_print_operation_get_print_settings(operation);
822         path = g_build_filename(get_rc_dir(), PRINT_SETTINGS, NULL);
823
824         gtk_print_settings_to_file(print_settings, path, &error);
825         if (error)
826                 {
827                 log_printf("Error: Print settings save failed:\n%s", error->message);
828                 g_error_free(error);
829                 error = NULL;
830                 }
831         g_free(path);
832         g_object_unref(print_settings);
833
834         page_setup = gtk_print_operation_get_default_page_setup(operation);
835         path = g_build_filename(get_rc_dir(), PAGE_SETUP, NULL);
836
837         gtk_page_setup_to_file(page_setup, path, &error);
838         if (error)
839                 {
840                 log_printf("Error: Print page setup save failed:\n%s", error->message);
841                 g_error_free(error);
842                 error = NULL;
843                 }
844         g_free(path);
845         g_object_unref(page_setup);
846
847         print_pref_store(pw);
848
849         work = pw->print_pixbuf_queue;
850         while (work)
851                 {
852                 pixbuf = work->data;
853                 if (pixbuf)
854                         {
855                         g_object_unref(pixbuf);
856                         }
857                 work = work->next;
858                 }
859         g_list_free(pw->print_pixbuf_queue);
860         g_object_unref(pw->page_text);
861         g_free(pw);
862 }
863
864 void print_window_new(FileData *fd, GList *selection, GList *list, GtkWidget *parent)
865 {
866         PrintWindow *pw;
867         GtkWidget *vbox;
868         GtkPrintOperation *operation;
869         GtkPageSetup *page_setup;
870         gchar *uri;
871         const gchar *dir;
872         GError *error = NULL;
873         gchar *path;
874         GtkPrintSettings *settings;
875
876         pw = g_new0(PrintWindow, 1);
877
878         pw->source_selection = file_data_process_groups_in_selection(selection, FALSE, NULL);
879
880         if (print_layout_page_count(pw) == 0)
881                 {
882                 return;
883                 }
884
885         pw->parent = parent;
886
887         vbox = gtk_vbox_new(FALSE, 0);
888         gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
889         gtk_widget_show(vbox);
890
891         print_text_menu(vbox, pw);
892         pw->vbox = vbox;
893
894         pw->print_pixbuf_queue = NULL;
895         pw->job_render_finished = FALSE;
896         pw->job_page = 0;
897
898         operation = gtk_print_operation_new();
899         settings = gtk_print_settings_new();
900
901         gtk_print_operation_set_custom_tab_label(operation, "Options");
902         gtk_print_operation_set_use_full_page(operation, TRUE);
903         gtk_print_operation_set_unit(operation, GTK_UNIT_POINTS);
904         gtk_print_operation_set_embed_page_setup(operation, TRUE);
905         gtk_print_operation_set_allow_async (operation, TRUE);
906         dir = g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS);
907         if (dir == NULL)
908                 {
909                 dir = g_get_home_dir();
910                 }
911
912         uri = g_build_filename("file:/", dir, "geeqie-file.pdf", NULL);
913         gtk_print_settings_set(settings, GTK_PRINT_SETTINGS_OUTPUT_URI, uri);
914         g_free(uri);
915
916         path = g_build_filename(get_rc_dir(), PRINT_SETTINGS, NULL);
917         gtk_print_settings_load_file(settings, path, &error);
918         if (error)
919                 {
920                 log_printf("Error: Printer settings load failed:\n%s", error->message);
921                 g_error_free(error);
922                 error = NULL;
923                 }
924         gtk_print_operation_set_print_settings(operation, settings);
925         g_free(path);
926
927         page_setup = gtk_page_setup_new();
928         path = g_build_filename(get_rc_dir(), PAGE_SETUP, NULL);
929         gtk_page_setup_load_file(page_setup, path, &error);
930         if (error)
931                 {
932                 log_printf("Error: Print page setup load failed:\n%s", error->message);
933                 g_error_free(error);
934                 error = NULL;
935                 }
936         gtk_print_operation_set_default_page_setup(operation, page_setup);
937         g_free(path);
938
939         g_signal_connect (G_OBJECT (operation), "begin-print",
940                                         G_CALLBACK (begin_print), pw);
941         g_signal_connect (G_OBJECT (operation), "draw-page",
942                                         G_CALLBACK (draw_page), pw);
943         g_signal_connect (G_OBJECT (operation), "end-print",
944                                         G_CALLBACK (end_print_cb), pw);
945         g_signal_connect (G_OBJECT (operation), "create-custom-widget",
946                                         G_CALLBACK (option_tab_cb), pw);
947         g_signal_connect (G_OBJECT (operation), "paginate",
948                                         G_CALLBACK (paginate_cb), pw);
949
950         gtk_print_operation_set_n_pages(operation, print_layout_page_count(pw));
951
952         gtk_print_operation_run(operation, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
953                                                                                                 GTK_WINDOW (parent), &error);
954
955         if (error)
956                 {
957                 GtkWidget *dialog;
958
959                 dialog = gtk_message_dialog_new(GTK_WINDOW (parent),
960                                                                 GTK_DIALOG_DESTROY_WITH_PARENT,
961                                                                 GTK_MESSAGE_ERROR,
962                                                                 GTK_BUTTONS_CLOSE,
963                                                                 "%s", error->message);
964                 g_error_free (error);
965
966                 g_signal_connect(dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL);
967
968                 gtk_widget_show (dialog);
969                 }
970
971         g_object_unref(page_setup);
972         g_object_unref(settings);
973 }
974 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */