From 117237228b9c9171e184254fb0a4604c9f58673b Mon Sep 17 00:00:00 2001 From: Thomas White Date: Wed, 4 May 2016 12:05:02 +0200 Subject: Restore "Export PDF" and add initial printing stuff --- src/colloquium.c | 20 ++++-- src/narrative_window.c | 55 +++++++++++++-- src/print.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++ src/print.h | 32 +++++++++ src/render.c | 17 +++-- 5 files changed, 291 insertions(+), 18 deletions(-) create mode 100644 src/print.c create mode 100644 src/print.h (limited to 'src') diff --git a/src/colloquium.c b/src/colloquium.c index 52c831a..436ac86 100644 --- a/src/colloquium.c +++ b/src/colloquium.c @@ -76,11 +76,11 @@ static void about_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(window), PACKAGE_VERSION); gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(window), - "© 2013 Thomas White "); + "© 2016 Thomas White "); gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(window), - "A tiny presentation program"); + "Narrative-based presentation system"); gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(window), - "© 2013 Thomas White \n"); + "© 2016 Thomas White \n"); gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(window), "http://www.bitwiz.org.uk/"); gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(window), authors); @@ -191,6 +191,16 @@ static void colloquium_startup(GApplication *app) " " "
" " " + " Print..." + " win.print" + " " + " " + " Export slides as PDF..." + " win.exportpdf" + " " + "
" + "
" + " " " Load stylesheet" " win.loadstyle" " " @@ -198,10 +208,6 @@ static void colloquium_startup(GApplication *app) " Save stylesheet" " win.savestyle" " " - " " - " Export PDF" - " win.exportpdf" - " " "
" " " diff --git a/src/narrative_window.c b/src/narrative_window.c index 6d6baf3..f7cadc6 100644 --- a/src/narrative_window.c +++ b/src/narrative_window.c @@ -37,6 +37,7 @@ #include "render.h" #include "testcard.h" #include "pr_clock.h" +#include "print.h" struct _narrative_window @@ -133,12 +134,6 @@ static void save_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) } -static void exportpdf_sig(GSimpleAction *action, GVariant *parameter, - gpointer vp) -{ -} - - static void open_slidesorter_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) { @@ -307,11 +302,49 @@ static void testcard_sig(GSimpleAction *action, GVariant *parameter, } +static gint export_pdf_response_sig(GtkWidget *d, gint response, + struct presentation *p) +{ + if ( response == GTK_RESPONSE_ACCEPT ) { + char *filename; + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d)); + export_pdf(p, filename); + g_free(filename); + } + + gtk_widget_destroy(d); + + return 0; +} + + +static void exportpdf_sig(GSimpleAction *action, GVariant *parameter, + gpointer vp) +{ + struct presentation *p = vp; + GtkWidget *d; + + d = gtk_file_chooser_dialog_new("Export PDF", + NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Export", GTK_RESPONSE_ACCEPT, + NULL); + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d), + TRUE); + + g_signal_connect(G_OBJECT(d), "response", + G_CALLBACK(export_pdf_response_sig), p); + + gtk_widget_show_all(d); +} + + + GActionEntry nw_entries[] = { { "save", save_sig, NULL, NULL, NULL }, { "saveas", saveas_sig, NULL, NULL, NULL }, - { "exportpdf", exportpdf_sig, NULL, NULL, NULL }, { "sorter", open_slidesorter_sig, NULL, NULL, NULL }, { "deleteframe", delete_frame_sig, NULL, NULL, NULL }, { "slide", add_slide_sig, NULL, NULL, NULL }, @@ -326,6 +359,12 @@ GActionEntry nw_entries[] = { }; +GActionEntry nw_entries_p[] = { + { "print", print_sig, NULL, NULL, NULL }, + { "exportpdf", exportpdf_sig, NULL, NULL, NULL }, +}; + + static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event, NarrativeWindow *nw) { @@ -484,6 +523,8 @@ NarrativeWindow *narrative_window_new(struct presentation *p, GApplication *app) g_action_map_add_action_entries(G_ACTION_MAP(nw->window), nw_entries, G_N_ELEMENTS(nw_entries), nw); + g_action_map_add_action_entries(G_ACTION_MAP(nw->window), nw_entries_p, + G_N_ELEMENTS(nw_entries), p); nw_update_titlebar(nw); diff --git a/src/print.c b/src/print.c new file mode 100644 index 0000000..dfdbf83 --- /dev/null +++ b/src/print.c @@ -0,0 +1,185 @@ +/* + * print.c + * + * Copyright © 2016 Thomas White + * + * This file is part of Colloquium. + * + * Colloquium is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "presentation.h" +#include "narrative_window.h" +#include "render.h" + + +static GtkPrintSettings *print_settings = NULL; + +struct print_stuff +{ + struct presentation *p; + GtkWidget *combo; + int slides_only; + SCBlock *slide; +}; + + +static void print_widget_apply(GtkPrintOperation *op, GtkWidget *widget, + void *vp) +{ + const char *id; + struct print_stuff *ps = vp; + + id = gtk_combo_box_get_active_id(GTK_COMBO_BOX(ps->combo)); + if ( strcmp(id, "slides") == 0 ) { + ps->slides_only = 1; + } else { + ps->slides_only = 0; + } +} + + +static GObject *print_widget(GtkPrintOperation *op, void *vp) +{ + GtkWidget *vbox; + GtkWidget *cbox; + struct print_stuff *ps = vp; + + vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 10); + + /* What do you want to print? */ + cbox = gtk_combo_box_text_new(); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(cbox), "slides", + "Print the slides only"); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(cbox), "narrative", + "Print the narrative"); + gtk_box_pack_start(GTK_BOX(vbox), cbox, FALSE, FALSE, 10); + gtk_combo_box_set_active(GTK_COMBO_BOX(cbox), 1); + ps->combo = cbox; + + gtk_widget_show_all(vbox); + return G_OBJECT(vbox); + +} + + +static void print_slide_only(GtkPrintOperation *op, GtkPrintContext *ctx, + struct print_stuff *ps, int page) +{ + cairo_t *cr; + PangoContext *pc; + double w, h; + SCBlock *stylesheets[2]; + struct frame *top; + + cr = gtk_print_context_get_cairo_context(ctx); + pc = gtk_print_context_create_pango_context(ctx); + w = gtk_print_context_get_width(ctx); + h = gtk_print_context_get_height(ctx); + + stylesheets[0] = ps->p->stylesheet; + stylesheets[1] = NULL; + + cairo_rectangle(cr, 0.0, 0.0, w, h); + cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); + cairo_fill(cr); + + top = interp_and_shape(sc_block_child(ps->slide), stylesheets, NULL, + ps->p->is, ISZ_SLIDESHOW, + page+1, cr, + ps->p->slide_width, ps->p->slide_height, + ps->p->lang); + + recursive_wrap(top, pc); + + recursive_draw(top, cr, ps->p->is, ISZ_SLIDESHOW, + 0.0, ps->p->slide_height); + + ps->slide = next_slide(ps->p, ps->slide); +} + + +static void print_begin(GtkPrintOperation *op, GtkPrintContext *ctx, void *vp) +{ + struct print_stuff *ps = vp; + + if ( ps->slides_only ) { + gtk_print_operation_set_n_pages(op, num_slides(ps->p)); + ps->slide = first_slide(ps->p); + } else { + /* FIXME */ + printf("Don't know how to print the narrative yet\n"); + } +} + + +static void print_draw(GtkPrintOperation *op, GtkPrintContext *ctx, gint page, + void *vp) +{ + struct print_stuff *ps = vp; + if ( ps->slides_only ) { + print_slide_only(op, ctx, ps, page); + } +} + + +void print_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) +{ + struct presentation *p = vp; + GtkPrintOperation *print; + GtkPrintOperationResult res; + struct print_stuff *ps; + + ps = malloc(sizeof(struct print_stuff)); + if ( ps == NULL ) return; + ps->p = p; + + print = gtk_print_operation_new(); + if ( print_settings != NULL ) { + gtk_print_operation_set_print_settings(print, print_settings); + } + + g_signal_connect(print, "create-custom-widget", + G_CALLBACK(print_widget), ps); + g_signal_connect(print, "custom-widget-apply", + G_CALLBACK(print_widget_apply), ps); + g_signal_connect(print, "begin_print", G_CALLBACK(print_begin), ps); + g_signal_connect(print, "draw_page", G_CALLBACK(print_draw), ps); + + res = gtk_print_operation_run(print, + GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, + GTK_WINDOW(NULL), NULL); + + if ( res == GTK_PRINT_OPERATION_RESULT_APPLY ) { + if ( print_settings != NULL ) { + g_object_unref(print_settings); + } + print_settings = g_object_ref( + gtk_print_operation_get_print_settings(print)); + } + g_object_unref(print); +} + diff --git a/src/print.h b/src/print.h new file mode 100644 index 0000000..4b998b1 --- /dev/null +++ b/src/print.h @@ -0,0 +1,32 @@ +/* + * print.h + * + * Copyright © 2016 Thomas White + * + * This file is part of Colloquium. + * + * Colloquium is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef PRINT_H +#define PRINT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +extern void print_sig(GSimpleAction *action, GVariant *parameter, gpointer vp); + +#endif /* PRINT_H */ diff --git a/src/render.c b/src/render.c index 8699ed8..a8ff7ea 100644 --- a/src/render.c +++ b/src/render.c @@ -226,7 +226,7 @@ struct frame *interp_and_shape(SCBlock *scblocks, SCBlock **stylesheets, } -static struct frame *render_sc_to_surface(SCBlock *scblocks, cairo_surface_t *surf, +static struct frame *render_sc_with_context(SCBlock *scblocks, cairo_t *cr, double log_w, double log_h, SCBlock **stylesheets, SCCallbackList *cbl, ImageStore *is, enum is_size isz, @@ -266,7 +266,7 @@ cairo_surface_t *render_sc(SCBlock *scblocks, int w, int h, cr = cairo_create(surf); pc = pango_cairo_create_context(cr); cairo_scale(cr, w/log_w, h/log_h); - top = render_sc_to_surface(scblocks, surf, cr, log_w, log_h, + top = render_sc_with_context(scblocks, cr, log_w, log_h, stylesheets, cbl, is, isz,slide_number, lang, pc); g_object_unref(pc); @@ -278,6 +278,14 @@ cairo_surface_t *render_sc(SCBlock *scblocks, int w, int h, } +static int safe_strcmp(const char *a, const char *b) +{ + if ( a == NULL ) return 1; + if ( b == NULL ) return 1; + return strcmp(a, b); +} + + int export_pdf(struct presentation *p, const char *filename) { double r; @@ -302,9 +310,10 @@ int export_pdf(struct presentation *p, const char *filename) pc = pango_cairo_create_context(cr); i = 1; + bl = p->scblocks; while ( bl != NULL ) { - if ( strcmp(sc_block_name(bl), "slide") != 0 ) { + if ( safe_strcmp(sc_block_name(bl), "slide") != 0 ) { bl = sc_block_next(bl); continue; } @@ -322,7 +331,7 @@ int export_pdf(struct presentation *p, const char *filename) cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); cairo_fill(cr); - render_sc_to_surface(sc_block_child(bl), surf, cr, p->slide_width, + render_sc_with_context(sc_block_child(bl), cr, p->slide_width, p->slide_height, stylesheets, NULL, p->is, ISZ_SLIDESHOW, i, p->lang, pc); -- cgit v1.2.3