diff options
Diffstat (limited to 'printing.c')
| -rw-r--r-- | printing.c | 761 |
1 files changed, 761 insertions, 0 deletions
diff --git a/printing.c b/printing.c new file mode 100644 index 0000000..e3b5431 --- /dev/null +++ b/printing.c @@ -0,0 +1,761 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#include <math.h> + +#define LIST_UNITS(X, ...)\ + X(UNIT_MILLIMETRES, "Millimetres", 72.0 / 25.4) __VA_ARGS__\ + X(UNIT_CENTIMETRES, "Centimetres", 72.0 / 2.54) __VA_ARGS__\ + X(UNIT_INCHES, "Inches", 72.0) __VA_ARGS__\ + X(UNIT_MODERN_POINTS, "Modern points (1/72 inch)", 1.0) __VA_ARGS__\ + X(UNIT_TRADITIONAL_POINTS, "Traditional points (1/72.27 inch)", 72.0 / 72.27) __VA_ARGS__\ + X(UNIT_PERCENT, "Percent of printable area", 0.01) + +#define LIST_HORIZONTAL_FIELDS(X, ...)\ + X(FIELD_WIDTH, "Width") __VA_ARGS__\ + X(FIELD_LEFT, "Left") __VA_ARGS__\ + X(FIELD_RIGHT, "Right") + +#define LIST_VERTICAL_FIELDS(X, ...)\ + X(FIELD_HEIGHT, "Height") __VA_ARGS__\ + X(FIELD_TOP, "Top") __VA_ARGS__\ + X(FIELD_BOTTOM, "Bottom") + +#define LIST_FIELDS(X, ...)\ + LIST_HORIZONTAL_FIELDS(X, __VA_ARGS__) __VA_ARGS__\ + LIST_VERTICAL_FIELDS(X, __VA_ARGS__) + +enum unit { +#define X(E, N, S) E + LIST_UNITS(X, COMMA) +#undef X +}; + +enum field { +#define X(E, N) E + LIST_FIELDS(X, COMMA) +#undef X +}; + +#define X_COUNT(...) 1u +#define NFIELDS (LIST_FIELDS(X_COUNT, +)) + +struct print_data { + GdkPixbuf *image; + double width; + double height; + double left; + double top; +}; + +struct positioning_widget { + struct print_data *data; + GtkWidget *unit; + GtkWidget *entry[NFIELDS]; + GtkWidget *preview; + double page_width; + double page_height; + double drag_start_x; + double drag_start_y; + double drag_start_left; + double drag_start_top; + int updating; + int dragging; +}; + +#define X(E, T) "_"T":" +static const char *const field_labels[] = { LIST_FIELDS(X, COMMA) }; +#undef X + +static int +horizontal(enum field field) +{ +#define X(E, T) if (field == E) return 1 + LIST_HORIZONTAL_FIELDS(X, ;); +#undef X + return 0; +} + +static double +unit_in_points(struct positioning_widget *widget, enum field field) +{ + enum unit unit = gtk_combo_box_get_active(GTK_COMBO_BOX(widget->unit)); + double ret; + switch (unit) { +#define X(E, N, S) case E: ret = (S); break + LIST_UNITS(X, ;); +#undef X + } + if (unit == UNIT_PERCENT) + ret *= horizontal(field) ? widget->page_width : widget->page_height; + return ret; +} + +static double +points_to_unit(struct positioning_widget *widget, enum field field, double value) +{ + return value / unit_in_points(widget, field); +} + +static double +unit_to_points(struct positioning_widget *widget, enum field field, double value) +{ + return value * unit_in_points(widget, field); +} + +static void +get_printable_size(GtkPageSetup *setup, double *width, double *height) +{ + *width = gtk_page_setup_get_paper_width(setup, GTK_UNIT_POINTS) - + gtk_page_setup_get_left_margin(setup, GTK_UNIT_POINTS) - + gtk_page_setup_get_right_margin(setup, GTK_UNIT_POINTS); + + *height = gtk_page_setup_get_paper_height(setup, GTK_UNIT_POINTS) - + gtk_page_setup_get_top_margin(setup, GTK_UNIT_POINTS) - + gtk_page_setup_get_bottom_margin(setup, GTK_UNIT_POINTS); + + *width = MAX(*width, 0.1); + *height = MAX(*height, 0.1); +} + +static double +get_preview_scale(GtkWidget *preview, struct positioning_widget *widget) +{ + int width = MAX(preview->allocation.width - 16, 1); + int height = MAX(preview->allocation.height - 16, 1); + double x = (double)width / widget->page_width; + double y = (double)height / widget->page_height; + return MIN(x, y); +} + +static double +get_field_value(struct positioning_widget *widget, enum field field) +{ + struct print_data *data = widget->data; + switch (field) { + case FIELD_WIDTH: return data->width; + case FIELD_HEIGHT: return data->height; + case FIELD_TOP: return data->top; + case FIELD_LEFT: return data->left; + case FIELD_RIGHT: return widget->page_width - data->left - data->width; + case FIELD_BOTTOM: return widget->page_height - data->top - data->height; + } + abort(); +} + +static int +set_field_value(struct positioning_widget *widget, enum field field, double value) +{ + struct print_data *data = widget->data; + int image_width = gdk_pixbuf_get_width(data->image); + int image_height = gdk_pixbuf_get_height(data->image); + double aspect, pos, size, page, pos_opp, size_opp, page_opp; + double new_pos, new_size, new_pos_opp, new_size_opp; + double *posp, *pos_oppp, *sizep, *size_oppp, limit; + + switch (field) { + case FIELD_WIDTH: + case FIELD_LEFT: + case FIELD_RIGHT: + posp = &data->left; + sizep = &data->width; + page = widget->page_width; + pos_oppp = &data->top; + size_oppp = &data->height; + page_opp = widget->page_height; + aspect = (double)image_height / (double)image_width; + break; + + case FIELD_HEIGHT: + case FIELD_TOP: + case FIELD_BOTTOM: + posp = &data->top; + sizep = &data->height; + page = widget->page_height; + pos_oppp = &data->left; + size_oppp = &data->width; + page_opp = widget->page_width; + aspect = (double)image_width / (double)image_height; + break; + } + + pos = *posp; + size = *sizep; + pos_opp = *pos_oppp; + size_opp = *size_oppp; + + switch (field) { + case FIELD_WIDTH: + case FIELD_HEIGHT: + limit = page_opp / aspect; + limit = MIN(page, limit); + new_size = MIN(MAX(0.0, value), limit); + new_size_opp = new_size * aspect; + new_pos = pos + 0.5 * (size - new_size); + new_pos = MIN(MAX(0.0, new_pos), page - new_size); + new_pos_opp = pos_opp + 0.5 * (size_opp - new_size_opp); + new_pos_opp = MIN(MAX(0.0, new_pos_opp), page_opp - new_size_opp); + break; + + case FIELD_LEFT: + case FIELD_TOP: + value = MAX(value, 0.0); + new_pos = value; + new_size = pos + size - new_pos; + new_size_opp = new_size * aspect; + if (new_size < 0.0 || new_size_opp > page_opp) { + new_size = size; + new_size_opp = size_opp; + new_pos = MIN(MAX(0.0, value), page - new_size); + new_pos_opp = pos_opp; + } else { + new_pos_opp = pos_opp + 0.5 * (size_opp - new_size_opp); + new_pos_opp = MIN(MAX(0.0, new_pos_opp), page_opp - new_size_opp); + } + break; + + case FIELD_RIGHT: + case FIELD_BOTTOM: + value = MAX(value, 0.0); + new_pos = pos; + new_size = page - new_pos - value; + new_size_opp = new_size * aspect; + if (new_size < 0.0 || new_size_opp > page_opp) { + new_size = size; + new_size_opp = size_opp; + limit = page - new_size; + new_pos = limit - value; + new_pos = MIN(MAX(0.0, new_pos), limit); + new_pos_opp = pos_opp; + } else { + new_pos_opp = pos_opp + 0.5 * (size_opp - new_size_opp); + new_pos_opp = MIN(MAX(0.0, new_pos_opp), page_opp - new_size_opp); + } + break; + } + + *posp = new_pos; + *sizep = new_size; + *pos_oppp = new_pos_opp; + *size_oppp = new_size_opp; + return 1; +} + +static enum field +get_positioning_field(struct positioning_widget *widget, GtkWidget *entry) +{ + enum field field = 0u; + while (field < NFIELDS && widget->entry[field] != entry) + field++; + return field; +} + +static int +positioning_preview_expose(GtkWidget *preview, GdkEventExpose *event, void *user) +{ + struct positioning_widget *widget = user; + struct print_data *data = widget->data; + double scale = get_preview_scale(preview, widget); + double w = scale * widget->page_width; + double h = scale * widget->page_height; + double image_scale; + double page_x = preview->allocation.width - 8.0 - w; + double page_y = 8.0; + int image_width; + cairo_t *cr; + + cr = gdk_cairo_create(preview->window); + + cairo_rectangle(cr, event->area.x, event->area.y, event->area.width, event->area.height); + cairo_clip(cr); + gdk_cairo_set_source_color(cr, &preview->style->bg[GTK_STATE_NORMAL]); + cairo_paint(cr); + + cairo_rectangle(cr, page_x, page_y, w, h); + cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); + cairo_fill(cr); + + cairo_save(cr); + + cairo_rectangle(cr, page_x, page_y, w, h); + cairo_clip(cr); + image_width = gdk_pixbuf_get_width(data->image); + image_scale = scale * data->width / (double)image_width; + cairo_translate(cr, page_x + scale * data->left, page_y + scale * data->top); + cairo_scale(cr, image_scale, image_scale); + gdk_cairo_set_source_pixbuf(cr, data->image, 0.0, 0.0); + cairo_paint(cr); + + cairo_restore(cr); + + cairo_rectangle(cr, page_x, page_y, w, h); + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + cairo_set_line_width(cr, 1.0); + cairo_stroke(cr); + cairo_destroy(cr); + return 0; +} + +static int +positioning_preview_button_pressed(GtkWidget *preview, GdkEventButton *event, void *user) +{ + struct positioning_widget *widget = user; + struct print_data *data = widget->data; + double scale = get_preview_scale(preview, widget); + double page_x = preview->allocation.width - 8.0 - scale * widget->page_width; + double page_y = 8.0; + double image_x = page_x + scale * data->left; + double image_y = page_y + scale * data->top; + + if (event->button != 1 || + image_x > event->x || event->x > image_x + scale * data->width || + image_y > event->y || event->y > image_y + scale * data->height) + return 0; + + widget->drag_start_x = event->x; + widget->drag_start_y = event->y; + widget->drag_start_left = data->left; + widget->drag_start_top = data->top; + widget->dragging = 1; + return 1; +} + +static void +update_positioning_widget(struct positioning_widget *widget, enum field active_field) +{ + struct print_data *data = widget->data; + double x, y, value, scale = 1.0; + enum field field; + char *text; + int len, r; + + if (data->width > 0.0 && data->height > 0.0) { + x = widget->page_width / data->width; + y = widget->page_height / data->height; + scale = MIN(x, y); + if (scale < 1.0) { + data->width *= scale; + data->height *= scale; + } + } + + x = widget->page_width - data->width; + y = widget->page_height - data->height; + data->left = MIN(MAX(0.0, data->left), x); + data->top = MIN(MAX(0.0, data->top), y); + + widget->updating = 1; + + for (field = 0u; field < NFIELDS; field++) { + if (field == active_field) + continue; + + value = points_to_unit(widget, field, get_field_value(widget, field)); + + len = snprintf(NULL, 0u, "%.2f", value); + if (len < 0) eprintf("snprintf:"); + + text = malloc((size_t)len + 1u); + if (!text) abort(); + + r = sprintf(text, "%.2f", value); + if (r < 0) eprintf("snprintf:"); + if (r > len) abort(); + + gtk_entry_set_text(GTK_ENTRY(widget->entry[field]), text); + free(text); + } + + widget->updating = 0; + if (widget->preview) + gtk_widget_queue_draw(widget->preview); +} + +static int +positioning_preview_motion(GtkWidget *preview, GdkEventMotion *event, void *user) +{ + struct positioning_widget *widget = user; + struct print_data *data = widget->data; + double scale; + double left; + double top; + + if (!widget->dragging) + return 0; + + scale = get_preview_scale(preview, widget); + left = widget->drag_start_left + (event->x - widget->drag_start_x) / scale; + left = MIN(MAX(0.0, left), widget->page_width - data->width); + top = widget->drag_start_top + (event->y - widget->drag_start_y) / scale; + top = MIN(MAX(0.0, top), widget->page_height - data->height); + data->left = left; + data->top = top; + update_positioning_widget(widget, NFIELDS); + return 1; +} + +static int +positioning_preview_button_released(GtkWidget *preview, GdkEventButton *event, void *user) +{ + struct positioning_widget *widget = user; + (void) preview; + if (event->button != 1 || !widget->dragging) + return 0; + widget->dragging = 0; + return 1; +} + +static int +positioning_preview_scrolled(GtkWidget *preview, GdkEventScroll *event, void *user) +{ + struct positioning_widget *widget = user; + struct print_data *data = widget->data; + int image_width, image_height; + double aspect, amount, scale, page_x; + double pointer_x, pointer_y; + double maximum, width, height; + + if (!(event->state & GDK_CONTROL_MASK)) + return 0; + + switch (event->direction) { + case GDK_SCROLL_UP: amount = +0.02; break; + case GDK_SCROLL_DOWN: amount = -0.02; break; + case GDK_SCROLL_LEFT: + case GDK_SCROLL_RIGHT: + default: + return 0; + } + amount *= widget->page_width; + + image_width = gdk_pixbuf_get_width(data->image); + image_height = gdk_pixbuf_get_height(data->image); + aspect = (double)image_width / (double)image_height; + + maximum = MIN(widget->page_width, widget->page_height * aspect); + width = CLAMP(data->width + amount, 0.0, maximum); + height = width / aspect; + + scale = get_preview_scale(preview, widget); + page_x = preview->allocation.width - 8.0 - scale * widget->page_width; + pointer_x = (event->x - page_x) / scale; + pointer_y = (event->y - 8.0) / scale; + if (data->width > 0.0) { + data->left = pointer_x - (pointer_x - data->left) * width / data->width; + data->top = pointer_y - (pointer_y - data->top) * height / data->height; + } + data->width = width; + data->height = height; + update_positioning_widget(widget, NFIELDS); + return 1; +} + +static int +get_entry_value(GtkEntry *entry, double *value) +{ + const char *text = gtk_entry_get_text(entry); + char *end; + double parsed = strtod(text, &end); + while (isspace(*(unsigned char *)end)) + end++; + if (end == text || *end || !isfinite(parsed)) + return 0; + *value = parsed; + return 1; +} + +static void +adjust_positioning_field(struct positioning_widget *widget, enum field field, double amount) +{ + double value; + + if (field == NFIELDS) + return; + + value = get_field_value(widget, field); + value = points_to_unit(widget, field, value); + value += amount; + value = unit_to_points(widget, field, value); + + if (set_field_value(widget, field, value)) + update_positioning_widget(widget, NFIELDS); +} + +static int +positioning_entry_key_pressed(GtkWidget *entry, GdkEventKey *event, void *user) +{ + struct positioning_widget *widget = user; + enum field field = get_positioning_field(widget, entry); + double amount; + switch (event->keyval) { + case GDK_Up: amount = +1.0; break; + case GDK_Down: amount = -1.0; break; + case GDK_Page_Up: amount = +10.0; break; + case GDK_Page_Down: amount = -10.0; break; + default: + return 0; + } + adjust_positioning_field(widget, field, amount); + return 1; +} + +static int +positioning_entry_scrolled(GtkWidget *entry, GdkEventScroll *event, void *user) +{ + struct positioning_widget *widget = user; + enum field field = get_positioning_field(widget, entry); + if (event->direction == GDK_SCROLL_UP) + adjust_positioning_field(widget, field, +1.0); + else if (event->direction == GDK_SCROLL_DOWN) + adjust_positioning_field(widget, field, -1.0); + else + return 0; + return 1; +} + +static void +positioning_entry_inserted(GtkEditable *editable, const char *text, int length, int *position, void *user) +{ + (void) position; + (void) user; + if (memchr(text, '-', (size_t)length)) + g_signal_stop_emission_by_name(editable, "insert-text"); +} + +static void +positioning_entry_changed(GtkEditable *editable, void *user) +{ + struct positioning_widget *widget = user; + enum field field; + double value; + + if (widget->updating) + return; + + for (field = 0; field < NFIELDS; field++) + if (GTK_EDITABLE(widget->entry[field]) == editable) + goto have_field; + return; + +have_field: + if (get_entry_value(GTK_ENTRY(widget->entry[field]), &value)) { + value = unit_to_points(widget, field, value); + if (!set_field_value(widget, field, value)) + field = NFIELDS; + update_positioning_widget(widget, field); + } +} + +static void +positioning_unit_changed(GtkComboBox *combo, void *user) +{ + struct positioning_widget *widget = user; + (void) combo; + if (!widget->updating) + update_positioning_widget(widget, NFIELDS); +} + +static void +begin_print(GtkPrintOperation *operation, GtkPrintContext *context, void *user) +{ + (void) context; + (void) user; + gtk_print_operation_set_n_pages(operation, 1); +} + +static int +positioning_entry_focus_out(GtkWidget *entry, GdkEventFocus *event, void *user) +{ + struct positioning_widget *widget = user; + (void) entry; + (void) event; + if (!widget->updating) + update_positioning_widget(widget, NFIELDS); + return 0; +} + +static GtkWidget * +create_positioning_widget(GtkPrintOperation *operation, void *user) +{ +#define X(E, N, S) N + static const char *const unit_names[] = {LIST_UNITS(X, COMMA)}; +#undef X + +#define X(E, T) E + static const enum field field_layout[2][3] = { + {LIST_HORIZONTAL_FIELDS(X, COMMA)}, + {LIST_VERTICAL_FIELDS(X, COMMA)} + }; +#undef X + + struct print_data *data = user; + struct positioning_widget *positioning; + GtkPageSetup *setup; + GtkWidget *box, *grid, *label; + enum field field; + size_t unit; + unsigned int row, column; + + positioning = g_new0(struct positioning_widget, 1); + positioning->data = data; + setup = gtk_print_operation_get_default_page_setup(operation); + get_printable_size(setup, &positioning->page_width, &positioning->page_height); + + box = gtk_hbox_new(0, 12); + grid = gtk_table_new(4, 4, 0); + gtk_container_set_border_width(GTK_CONTAINER(grid), 8); + gtk_table_set_row_spacings(GTK_TABLE(grid), 6); + gtk_table_set_col_spacings(GTK_TABLE(grid), 6); + label = gtk_label_new_with_mnemonic("_Units:"); + gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f); + gtk_table_attach(GTK_TABLE(grid), label, 0, 1, 0, 1, GTK_FILL, 0, 4u, 4u); + positioning->unit = gtk_combo_box_new_text(); + for (unit = 0; unit < ELEMSOF(unit_names); unit++) + gtk_combo_box_append_text(GTK_COMBO_BOX(positioning->unit), unit_names[unit]); + gtk_combo_box_set_active(GTK_COMBO_BOX(positioning->unit), UNIT_MILLIMETRES); + gtk_label_set_mnemonic_widget(GTK_LABEL(label), positioning->unit); + gtk_table_attach(GTK_TABLE(grid), positioning->unit, 1, 4, 0, 1, GTK_EXPAND | GTK_FILL, 0, 4u, 4u); + + for (field = 0; field < NFIELDS; field++) { + positioning->entry[field] = gtk_entry_new(); + gtk_entry_set_width_chars(GTK_ENTRY(positioning->entry[field]), 12); + gtk_widget_add_events(positioning->entry[field], GDK_SCROLL_MASK); + g_signal_connect(positioning->entry[field], "changed", + G_CALLBACK(&positioning_entry_changed), positioning); + g_signal_connect(positioning->entry[field], "focus-out-event", + G_CALLBACK(&positioning_entry_focus_out), positioning); + g_signal_connect(positioning->entry[field], "insert-text", + G_CALLBACK(&positioning_entry_inserted), positioning); + g_signal_connect(positioning->entry[field], "key-press-event", + G_CALLBACK(&positioning_entry_key_pressed), positioning); + g_signal_connect(positioning->entry[field], "scroll-event", + G_CALLBACK(&positioning_entry_scrolled), positioning); + } + for (row = 0; row < 3; row++) { + for (column = 0; column < 2; column++) { + field = field_layout[column][row]; + label = gtk_label_new_with_mnemonic(field_labels[field]); + gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f); + gtk_label_set_mnemonic_widget(GTK_LABEL(label), positioning->entry[field]); + gtk_table_attach(GTK_TABLE(grid), label, 2 * column, 2 * column + 1, + row + 1, row + 2, GTK_FILL, 0, 4u, 4u); + gtk_table_attach(GTK_TABLE(grid), positioning->entry[field], + 2 * column + 1, 2 * column + 2, row + 1, row + 2, + GTK_FILL, 0, 4u, 4u); + } + } + positioning->preview = gtk_drawing_area_new(); + gtk_widget_set_size_request(positioning->preview, 200, 200); + gtk_widget_add_events(positioning->preview, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK); + g_signal_connect(positioning->preview, "expose-event", + G_CALLBACK(&positioning_preview_expose), positioning); + g_signal_connect(positioning->preview, "button-press-event", + G_CALLBACK(&positioning_preview_button_pressed), positioning); + g_signal_connect(positioning->preview, "motion-notify-event", + G_CALLBACK(&positioning_preview_motion), positioning); + g_signal_connect(positioning->preview, "scroll-event", + G_CALLBACK(&positioning_preview_scrolled), positioning); + g_signal_connect(positioning->preview, "button-release-event", + G_CALLBACK(&positioning_preview_button_released), positioning); + gtk_box_pack_start(GTK_BOX(box), grid, 0, 0, 0u); + gtk_box_pack_start(GTK_BOX(box), positioning->preview, 1, 1, 0u); + g_signal_connect(positioning->unit, "changed", G_CALLBACK(&positioning_unit_changed), positioning); + g_object_set_data_full(G_OBJECT(box), "positioning", positioning, g_free); + update_positioning_widget(positioning, NFIELDS); + gtk_widget_show_all(box); + return box; +} + +static void +apply_print_positioning(GtkPrintOperation *operation, GtkWidget *widget, void *user) +{ + struct positioning_widget *positioning = g_object_get_data(G_OBJECT(widget), "positioning"); + (void) operation; + (void) user; + if (positioning) + update_positioning_widget(positioning, NFIELDS); +} + +static void +update_print_positioning(GtkPrintOperation *operation, GtkWidget *widget, GtkPageSetup *setup, + GtkPrintSettings *settings, void *user) +{ + struct positioning_widget *positioning = g_object_get_data(G_OBJECT(widget), "positioning"); + (void) operation; + (void) settings; + (void) user; + if (positioning) { + get_printable_size(setup, &positioning->page_width, &positioning->page_height); + update_positioning_widget(positioning, NFIELDS); + } +} + +static void +draw_page(GtkPrintOperation *operation, GtkPrintContext *context, int page, void *user) +{ + struct print_data *data = user; + GdkPixbuf *image = data->image; + double scale; + cairo_t *cr; + + (void) operation; + (void) page; + + scale = data->width / gdk_pixbuf_get_width(image); + cr = gtk_print_context_get_cairo_context(context); + cairo_translate(cr, data->left, data->top); + cairo_scale(cr, scale, scale); + gdk_cairo_set_source_pixbuf(cr, image, 0.0, 0.0); + cairo_paint(cr); +} + +void +open_print(GdkPixbuf *image) +{ + struct print_data data; + GtkPrintOperation *operation; + GtkPageSetup *setup; + GtkPageOrientation orientation = GTK_PAGE_ORIENTATION_PORTRAIT; + double page_width, page_height, s, x, y; + int width, height; + + if (!image) + return; + + data.image = image; + g_object_ref(data.image); + + width = gdk_pixbuf_get_width(data.image); + height = gdk_pixbuf_get_height(data.image); + + if (width > height) + orientation = GTK_PAGE_ORIENTATION_LANDSCAPE; + + setup = gtk_page_setup_new(); + gtk_page_setup_set_orientation(setup, orientation); + get_printable_size(setup, &page_width, &page_height); + + x = page_width / (double)width; + y = page_height / (double)height; + s = MIN(x, y); + data.width = s * width; + data.height = s * height; + data.left = 0.5 * (page_width - data.width); + data.top = 0.5 * (page_height - data.height); + + operation = gtk_print_operation_new(); + gtk_print_operation_set_default_page_setup(operation, setup); + g_object_unref(setup); + gtk_print_operation_set_embed_page_setup(operation, 1); + gtk_print_operation_set_custom_tab_label(operation, "Positioning"); + + g_signal_connect(operation, "create-custom-widget", G_CALLBACK(&create_positioning_widget), &data); + g_signal_connect(operation, "custom-widget-apply", G_CALLBACK(&apply_print_positioning), &data); + g_signal_connect(operation, "update-custom-widget", G_CALLBACK(&update_print_positioning), &data); + g_signal_connect(operation, "begin-print", G_CALLBACK(&begin_print), &data); + g_signal_connect(operation, "draw-page", G_CALLBACK(&draw_page), &data); + + gtk_print_operation_run(operation, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, GTK_WINDOW(window), NULL); + g_object_unref(operation); + g_object_unref(data.image); +} |
