diff --git a/ChangeLog b/ChangeLog index 1241e4fbf3..6085d0fb4c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2007-07-19 Sven Neumann + + Applied patch from Stefan attached to bug #387604: + + * plug-ins/print/Makefile.am + * plug-ins/print/print-preview.[ch]: new files implementing a + print preview similar to GimpOffsetArea. + + * plug-ins/print/print.[ch] + * plug-ins/print/print-page-layout.c + * plug-ins/print/print-settings.c: adds GUI to adjust the offsets. + 2007-07-19 Sven Neumann * app/core/gimpimage.[ch]: renamed gimp_image_active_drawable() to diff --git a/plug-ins/print/Makefile.am b/plug-ins/print/Makefile.am index 52d5748fd7..63dd7d18ea 100644 --- a/plug-ins/print/Makefile.am +++ b/plug-ins/print/Makefile.am @@ -44,5 +44,7 @@ print_SOURCES = \ print-draw-page.h \ print-page-layout.c \ print-page-layout.h \ + print-preview.c \ + print-preview.h \ print-settings.c \ print-settings.h diff --git a/plug-ins/print/print-page-layout.c b/plug-ins/print/print-page-layout.c index e14fb1dce5..d4a201e14d 100644 --- a/plug-ins/print/print-page-layout.c +++ b/plug-ins/print/print-page-layout.c @@ -25,6 +25,7 @@ #include "print.h" #include "print-page-layout.h" +#include "print-preview.h" #include "libgimp/stdplugins-intl.h" @@ -36,8 +37,10 @@ typedef struct gint image_height; GimpSizeEntry *size_entry; GimpSizeEntry *resolution_entry; + GimpSizeEntry *offset_entry; GimpChainButton *chain; GtkWidget *area_label; + GtkWidget *preview; } PrintSizeInfo; @@ -45,15 +48,21 @@ static void run_page_setup_dialog (GtkWidget *widget, PrintData *data); static GtkWidget * print_size_frame (PrintData *data); +static GtkWidget * print_offset_frame (PrintData *data); static void print_size_info_size_changed (GtkWidget *widget); static void print_size_info_resolution_changed (GtkWidget *widget); static void print_size_info_unit_changed (GtkWidget *widget); static void print_size_info_chain_toggled (GtkWidget *widget); - -static void print_size_info_set_size (PrintSizeInfo *info, - gdouble width, - gdouble height); +static void print_size_info_offset_changed (GtkWidget *widget); +static void print_size_info_preview_offset_changed + (GtkWidget *widget, + gdouble offset_x, + gdouble offset_y); +static void print_size_info_center_clicked (GtkWidget *widget, + gpointer data); +static void print_size_info_use_full_page_toggled + (GtkWidget *widget); static void print_size_info_set_resolution (PrintSizeInfo *info, gdouble xres, @@ -69,11 +78,14 @@ static PrintSizeInfo info; GtkWidget * print_page_layout_gui (PrintData *data) { - GtkWidget *main_vbox; - GtkWidget *hbox; - GtkWidget *button; - GtkWidget *label; - GtkWidget *frame; + GtkWidget *main_vbox; + GtkWidget *main_hbox; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *button; + GtkWidget *label; + GtkWidget *frame; + GtkPageSetup *setup; memset (&info, 0, sizeof (PrintSizeInfo)); @@ -84,8 +96,17 @@ print_page_layout_gui (PrintData *data) main_vbox = gtk_vbox_new (FALSE, 12); gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12); + main_hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, TRUE, TRUE, 0); + gtk_box_set_spacing (GTK_BOX(main_hbox), 12); + gtk_widget_show (main_hbox); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (main_hbox), vbox, FALSE, FALSE, 0); + gtk_widget_show (vbox); + hbox = gtk_hbox_new (FALSE, 0); - gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); button = gtk_button_new_with_mnemonic (_("_Adjust Page Size " @@ -113,7 +134,7 @@ print_page_layout_gui (PrintData *data) /* label for the printable area */ hbox = gtk_hbox_new (FALSE, 6); - gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); label = gtk_label_new (_("Printable area:")); @@ -132,14 +153,36 @@ print_page_layout_gui (PrintData *data) /* size entry area for the image's print size */ - hbox = gtk_hbox_new (FALSE, 0); - gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0); - gtk_widget_show (hbox); - frame = print_size_frame (data); - gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 12); gtk_widget_show (frame); + /* offset entry area for the image's offset position */ + + frame = print_offset_frame (data); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + button = gtk_check_button_new_with_label (_("Ignore Page Margins")); + data->use_full_page = FALSE; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + g_signal_connect (button, "toggled", + G_CALLBACK (print_size_info_use_full_page_toggled), + NULL); + gtk_widget_show (button); + + setup = gtk_print_operation_get_default_page_setup (data->operation); + + info.preview = gimp_print_preview_new (setup, data->drawable_id); + gtk_box_pack_start (GTK_BOX (main_hbox), + info.preview, TRUE, TRUE, 0); + gtk_widget_show (info.preview); + + g_signal_connect (info.preview, "offsets-changed", + G_CALLBACK (print_size_info_preview_offset_changed), + NULL); + print_size_info_set_page_setup (&info); return main_vbox; @@ -172,6 +215,9 @@ run_page_setup_dialog (GtkWidget *widget, gtk_print_operation_set_default_page_setup (operation, page_setup); + gimp_print_preview_set_page_setup (GIMP_PRINT_PREVIEW (info.preview), + page_setup); + print_size_info_set_page_setup (&info); } @@ -216,7 +262,7 @@ print_size_frame (PrintData *data) entry = gimp_size_entry_new (1, data->unit, "%p", FALSE, FALSE, FALSE, SB_WIDTH, - GIMP_SIZE_ENTRY_UPDATE_NONE); + GIMP_SIZE_ENTRY_UPDATE_SIZE); gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0); gtk_widget_show (entry); @@ -278,11 +324,12 @@ print_size_frame (PrintData *data) gtk_size_group_add_widget (entry_group, height); - gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (entry), - _("_X resolution:"), 0, 0, 0.0); + label = gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (entry), + _("_X resolution:"), 0, 0, 0.0); + gtk_size_group_add_widget (label_group, label); + label = gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (entry), _("_Y resolution:"), 1, 0, 0.0); - gtk_size_group_add_widget (label_group, label); gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (entry), 0, @@ -303,6 +350,7 @@ print_size_frame (PrintData *data) info.chain = GIMP_CHAIN_BUTTON (chain); + g_signal_connect (info.size_entry, "value-changed", G_CALLBACK (print_size_info_size_changed), NULL); @@ -319,6 +367,204 @@ print_size_frame (PrintData *data) return frame; } +static GtkWidget * +print_offset_frame (PrintData *data) +{ + GtkWidget *entry; + GtkWidget *height; + GtkWidget *button; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *hbuttonbox; + GtkWidget *frame; + GtkWidget *label; + GtkSizeGroup *label_group; + GtkSizeGroup *entry_group; + GtkObject *adj; + + frame = gimp_frame_new (_("Image Offset")); + + vbox = gtk_vbox_new (FALSE, 12); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_widget_show (vbox); + + label_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + entry_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + + /* the offset entry */ + + hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + gtk_widget_show (hbox); + + entry = gimp_size_entry_new (1, data->unit, "%p", + FALSE, FALSE, FALSE, SB_WIDTH, + GIMP_SIZE_ENTRY_UPDATE_SIZE); + gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0); + gtk_widget_show (entry); + + info.offset_entry = GIMP_SIZE_ENTRY (entry); + + gtk_table_set_row_spacings (GTK_TABLE (entry), 2); + gtk_table_set_col_spacing (GTK_TABLE (entry), 0, 6); + gtk_table_set_col_spacing (GTK_TABLE (entry), 2, 6); + + height = gimp_spin_button_new (&adj, 1, 1, 1, 1, 10, 0, 1, 2); + gimp_size_entry_add_field (GIMP_SIZE_ENTRY (entry), + GTK_SPIN_BUTTON (height), NULL); + gtk_table_attach_defaults (GTK_TABLE (entry), height, 1, 2, 0, 1); + gtk_widget_show (height); + + gtk_size_group_add_widget (entry_group, height); + g_object_unref (entry_group); + + label = gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (entry), + _("X:"), 0, 0, 0.0); + gtk_size_group_add_widget (label_group, label); + + label = gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (entry), + _("Y:"), 1, 0, 0.0); + gtk_size_group_add_widget (label_group, label); + g_object_unref (label_group); + + gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (entry), 0, + 72.0, FALSE); + gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (entry), 1, + 72.0, FALSE); + + gimp_size_entry_set_value (GIMP_SIZE_ENTRY (entry), 0, 0); + gimp_size_entry_set_value (GIMP_SIZE_ENTRY (entry), 1, 0); + + g_signal_connect (info.offset_entry, "value-changed", + G_CALLBACK (print_size_info_offset_changed), + NULL); + + hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + gtk_widget_show (hbox); + + label = gtk_label_new (_("Center:")); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + hbuttonbox = gtk_hbutton_box_new (); + gtk_box_pack_start (GTK_BOX (hbox), hbuttonbox, FALSE, FALSE, 6); + gtk_button_box_set_layout (GTK_BUTTON_BOX(hbuttonbox), GTK_BUTTONBOX_START); + gtk_widget_show (hbuttonbox); + + button = gtk_button_new_with_mnemonic (_("Horizontally")); + gtk_container_add (GTK_CONTAINER (hbuttonbox), button); + g_signal_connect (button, "clicked", + G_CALLBACK (print_size_info_center_clicked), + GINT_TO_POINTER (1)); + gtk_widget_show (button); + + button = gtk_button_new_with_mnemonic (_("Vertically")); + gtk_container_add (GTK_CONTAINER (hbuttonbox), button); + g_signal_connect (button, "clicked", + G_CALLBACK (print_size_info_center_clicked), + GINT_TO_POINTER (2)); + gtk_widget_show (button); + + + return frame; +} + +static void +print_size_info_preview_offset_changed (GtkWidget *widget, + gdouble offset_x, + gdouble offset_y) +{ + info.data->offset_x = offset_x; + info.data->offset_y = offset_y; + + g_signal_handlers_block_by_func (info.offset_entry, + print_size_info_offset_changed, + NULL); + + gimp_size_entry_set_refval (info.offset_entry, 0, info.data->offset_x); + gimp_size_entry_set_refval (info.offset_entry, 1, info.data->offset_y); + + g_signal_handlers_unblock_by_func (info.offset_entry, + print_size_info_offset_changed, + NULL); +} + +static void +print_size_info_get_page_dimensions (PrintSizeInfo *info, + gdouble *page_width, + gdouble *page_height, + GtkUnit unit) +{ + GtkPageSetup *setup; + + setup = gtk_print_operation_get_default_page_setup (info->data->operation); + + if (info->data->use_full_page) + { + *page_width = gtk_page_setup_get_paper_width (setup, unit); + *page_height = gtk_page_setup_get_paper_height (setup, unit); + } else { + *page_width = gtk_page_setup_get_page_width (setup, unit); + *page_height = gtk_page_setup_get_page_height (setup, unit); + } + +} + +static void +gimp_size_info_get_max_offsets (gdouble *offset_x_max, + gdouble *offset_y_max) +{ + gdouble width; + gdouble height; + + print_size_info_get_page_dimensions (&info, &width, &height, GTK_UNIT_POINTS); + + *offset_x_max = width - 72.0 * info.image_width / info.data->xres; + *offset_x_max = MAX (0, *offset_x_max); + + *offset_y_max = height - 72.0 * info.image_height / info.data->yres; + *offset_y_max = MAX (0, *offset_y_max); +} + +static void +print_size_info_center_clicked (GtkWidget *widget, gpointer data) +{ + gdouble offset_x_max; + gdouble offset_y_max; + + gimp_size_info_get_max_offsets (&offset_x_max, &offset_y_max); + + switch (GPOINTER_TO_INT (data)) + { + case 0: + info.data->offset_x = offset_x_max / 2.0; + info.data->offset_y = offset_y_max / 2.0; + break; + case 1: + info.data->offset_x = offset_x_max / 2.0; + break; + case 2: + info.data->offset_y = offset_y_max / 2.0; + break; + } + + g_signal_handlers_block_by_func (info.offset_entry, + print_size_info_offset_changed, + NULL); + + gimp_size_entry_set_refval (info.offset_entry, 0, info.data->offset_x); + gimp_size_entry_set_refval (info.offset_entry, 1, info.data->offset_y); + + g_signal_handlers_unblock_by_func (info.offset_entry, + print_size_info_offset_changed, + NULL); + + gimp_print_preview_set_image_offsets (GIMP_PRINT_PREVIEW (info.preview), + info.data->offset_x, + info.data->offset_y); +} + static void print_size_info_size_changed (GtkWidget *widget) { @@ -365,7 +611,19 @@ print_size_info_unit_changed (GtkWidget *widget) h = gimp_size_entry_get_value (entry, 1) * factor; print_size_info_set_page_setup (&info); - print_size_info_set_size (&info, w, h); +} + +static void +print_size_info_use_full_page_toggled (GtkWidget *widget) +{ + gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); + + info.data->use_full_page = active; + + print_size_info_set_page_setup (&info); + + gimp_print_preview_set_use_full_page (GIMP_PRINT_PREVIEW(info.preview), + active); } static void @@ -375,20 +633,14 @@ print_size_info_chain_toggled (GtkWidget *widget) } static void -print_size_info_set_size (PrintSizeInfo *info, - gdouble width, - gdouble height) +print_size_info_offset_changed (GtkWidget *widget) { - g_signal_handlers_block_by_func (info->size_entry, - print_size_info_size_changed, - NULL); + info.data->offset_x = gimp_size_entry_get_refval (info.offset_entry, 0); + info.data->offset_y = gimp_size_entry_get_refval (info.offset_entry, 1); - gimp_size_entry_set_value (info->size_entry, 0, width); - gimp_size_entry_set_value (info->size_entry, 1, height); - - g_signal_handlers_unblock_by_func (info->size_entry, - print_size_info_size_changed, - NULL); + gimp_print_preview_set_image_offsets ( GIMP_PRINT_PREVIEW(info.preview), + info.data->offset_x, + info.data->offset_y); } static void @@ -396,17 +648,18 @@ print_size_info_set_resolution (PrintSizeInfo *info, gdouble xres, gdouble yres) { - PrintData *data = info->data; - - xres = CLAMP (xres, GIMP_MIN_RESOLUTION, GIMP_MAX_RESOLUTION); - yres = CLAMP (yres, GIMP_MIN_RESOLUTION, GIMP_MAX_RESOLUTION); + PrintData *data = info->data; + gdouble offset_x; + gdouble offset_y; + gdouble offset_x_max; + gdouble offset_y_max; if (info->chain && gimp_chain_button_get_active (info->chain)) { if (xres != data->xres) - yres = xres; + yres = xres; else - xres = yres; + xres = yres; } data->xres = xres; @@ -437,6 +690,39 @@ print_size_info_set_resolution (PrintSizeInfo *info, g_signal_handlers_unblock_by_func (info->size_entry, print_size_info_size_changed, NULL); + + gimp_size_info_get_max_offsets (&offset_x_max, &offset_y_max); + + offset_x = gimp_size_entry_get_refval (info->offset_entry, 0); + offset_y = gimp_size_entry_get_refval (info->offset_entry, 1); + + offset_x = CLAMP (offset_x, 0, offset_x_max); + offset_y = CLAMP (offset_y, 0, offset_y_max); + + data->offset_x = offset_x; + data->offset_y = offset_y; + + g_signal_handlers_block_by_func (info->offset_entry, + print_size_info_offset_changed, + NULL); + + gimp_size_entry_set_refval (info->offset_entry, 0, offset_x); + gimp_size_entry_set_refval (info->offset_entry, 1, offset_y); + + gimp_size_entry_set_refval_boundaries (info->offset_entry, 0, 0, offset_x_max); + gimp_size_entry_set_refval_boundaries (info->offset_entry, 1, 0, offset_y_max); + + g_signal_handlers_unblock_by_func (info->offset_entry, + print_size_info_offset_changed, + NULL); + + gimp_print_preview_set_image_dpi (GIMP_PRINT_PREVIEW (info->preview), + data->xres, data->yres); + + gimp_print_preview_set_image_offsets (GIMP_PRINT_PREVIEW (info->preview), + offset_x, offset_y); + gimp_print_preview_set_image_offsets_max (GIMP_PRINT_PREVIEW (info->preview), + offset_x_max, offset_y_max); } static void @@ -458,10 +744,10 @@ print_size_info_set_page_setup (PrintSizeInfo *info) gtk_print_operation_set_default_page_setup (data->operation, setup); } - page_width = (gtk_page_setup_get_page_width (setup, GTK_UNIT_INCH) * - gimp_unit_get_factor (data->unit)); - page_height = (gtk_page_setup_get_page_height (setup, GTK_UNIT_INCH) * - gimp_unit_get_factor (data->unit)); + print_size_info_get_page_dimensions (info, &page_width, &page_height, GTK_UNIT_INCH); + + page_width *= gimp_unit_get_factor (data->unit); + page_height *= gimp_unit_get_factor (data->unit); format = g_strdup_printf ("%%.%df x %%.%df %s", gimp_unit_get_digits (data->unit), @@ -478,21 +764,22 @@ print_size_info_set_page_setup (PrintSizeInfo *info) if (info->chain && gimp_chain_button_get_active (info->chain)) { - gdouble ratio; + gdouble ratio_x = page_width / (gdouble) info->image_width; + gdouble ratio_y = page_height / (gdouble) info->image_height; - ratio = (gdouble) info->image_width / (gdouble) info->image_height; - - if (ratio < 1.0) - x = y * ratio; + if (ratio_x < ratio_y) + y = (gdouble) info->image_height * ratio_x; else - y = x / ratio; + x = (gdouble) info->image_width * ratio_y; } gimp_size_entry_set_value_boundaries (info->size_entry, 0, 0.0, x); gimp_size_entry_set_value_boundaries (info->size_entry, 1, 0.0, y); - x = info->image_width / page_width; - y = info->image_height / page_height; + print_size_info_get_page_dimensions (info, &page_width, &page_height, GTK_UNIT_POINTS); + + x = (gdouble) info->image_width / page_width * 72.0; + y = (gdouble) info->image_height / page_height * 72.0; if (info->chain && gimp_chain_button_get_active (info->chain)) { diff --git a/plug-ins/print/print-preview.c b/plug-ins/print/print-preview.c new file mode 100644 index 0000000000..4f55d13bfd --- /dev/null +++ b/plug-ins/print/print-preview.c @@ -0,0 +1,531 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#include "print-preview.h" + + +#define DRAWING_AREA_SIZE 200 + + +enum +{ + OFFSETS_CHANGED, + LAST_SIGNAL +}; + + +static void gimp_print_preview_finalize (GObject *object); + +static gboolean gimp_print_preview_event (GtkWidget *widget, + GdkEvent *event, + GimpPrintPreview *preview); + +static gboolean gimp_print_preview_expose_event (GtkWidget *widget, + GdkEventExpose *eevent, + GimpPrintPreview *preview); + +static gdouble gimp_print_preview_get_scale (GimpPrintPreview *preview); + +static void gimp_print_preview_size_allocate (GtkWidget *widget, + GtkAllocation *allocation, + GimpPrintPreview *preview); + +static void gimp_print_preview_get_page_margins (GimpPrintPreview *preview, + gdouble *left_margin, + gdouble *right_margin, + gdouble *top_margin, + gdouble *bottom_margin); + + +G_DEFINE_TYPE (GimpPrintPreview, gimp_print_preview, GTK_TYPE_ASPECT_FRAME) + +#define parent_class gimp_print_preview_parent_class + +static guint gimp_print_preview_signals[LAST_SIGNAL] = { 0 }; + + +#define g_marshal_value_peek_double(v) (v)->data[0].v_double + +static void +marshal_VOID__DOUBLE_DOUBLE (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__DOUBLE_DOUBLE) (gpointer data1, + gdouble arg_1, + gdouble arg_2, + gpointer data2); + register GMarshalFunc_VOID__DOUBLE_DOUBLE callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + + callback = (GMarshalFunc_VOID__DOUBLE_DOUBLE) (marshal_data ? + marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_double (param_values + 1), + g_marshal_value_peek_double (param_values + 2), + data2); +} + +static void +gimp_print_preview_class_init (GimpPrintPreviewClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass*) klass; + + gimp_print_preview_signals[OFFSETS_CHANGED] = + g_signal_new ("offsets-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GimpPrintPreviewClass, offsets_changed), + NULL, NULL, + marshal_VOID__DOUBLE_DOUBLE, + G_TYPE_NONE, 2, + G_TYPE_DOUBLE, + G_TYPE_DOUBLE); + + gobject_class->finalize = gimp_print_preview_finalize; + + klass->offsets_changed = NULL; +} + +static void +gimp_print_preview_init (GimpPrintPreview *preview) +{ + preview->page = NULL; + preview->pixbuf = NULL; + preview->image_offset_x = 0.0; + preview->image_offset_y = 0.0; + preview->image_offset_x_max = 0.0; + preview->image_offset_y_max = 0.0; + preview->image_xres = 1.0; + preview->image_yres = 1.0; + preview->use_full_page = FALSE; + + preview->area = gtk_drawing_area_new(); + gtk_container_add (GTK_CONTAINER (preview), preview->area); + gtk_widget_show (preview->area); + + gtk_widget_set_events (GTK_WIDGET (preview->area), + GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK); +} + + +static void +gimp_print_preview_finalize (GObject *object) +{ + GimpPrintPreview *preview = GIMP_PRINT_PREVIEW (object); + + if (preview->pixbuf) + { + g_object_unref (preview->pixbuf); + preview->pixbuf = NULL; + } + + if (preview->page) + { + g_object_unref (preview->page); + preview->page = NULL; + } + + G_OBJECT_CLASS (gimp_print_preview_parent_class)->finalize (object); +} + +/** + * gimp_print_preview_new: + * @page: page setup + * @drawable_id: the drawable to print + * + * Creates a new #GimpPrintPreview widget. + * + * Return value: the new #GimpPrintPreview widget. + **/ +GtkWidget * +gimp_print_preview_new (GtkPageSetup *page, + gint32 drawable_id) +{ + GimpPrintPreview *preview; + gfloat ratio; + + preview = g_object_new (GIMP_TYPE_PRINT_PREVIEW, NULL); + + if (page != NULL) + preview->page = gtk_page_setup_copy (page); + else + preview->page = gtk_page_setup_new (); + + ratio = (gtk_page_setup_get_paper_width (preview->page, GTK_UNIT_POINTS) / + gtk_page_setup_get_paper_height (preview->page, GTK_UNIT_POINTS)); + + gtk_aspect_frame_set (GTK_ASPECT_FRAME (preview), 0.5, 0.5, ratio, FALSE); + + g_signal_connect (preview->area, "event", + G_CALLBACK (gimp_print_preview_event), + preview); + + g_signal_connect (preview->area, "expose-event", + G_CALLBACK (gimp_print_preview_expose_event), + preview); + + g_signal_connect (preview->area, "size-allocate", + G_CALLBACK (gimp_print_preview_size_allocate), + preview); + + gtk_widget_set_size_request (preview->area, + DRAWING_AREA_SIZE, DRAWING_AREA_SIZE); + + preview->drawable_id = drawable_id; + + return GTK_WIDGET (preview); +} + +/** + * gimp_print_preview_set_image_dpi: + * @preview: a #GimpPrintPreview. + * @xres: the X resolution + * @yres: the Y resolution + * + * Sets the resolution of the image/drawable displayed by the + * #GimpPrintPreview. + **/ +void +gimp_print_preview_set_image_dpi (GimpPrintPreview *preview, + gdouble xres, + gdouble yres) +{ + g_return_if_fail (GIMP_IS_PRINT_PREVIEW (preview)); + + if (preview->image_xres != xres || preview->image_yres != yres) + { + preview->image_xres = xres; + preview->image_yres = yres; + + gtk_widget_queue_draw (GTK_WIDGET (preview->area)); + } +} + +/** + * gimp_print_preview_set_page_setup: + * @preview: a #GimpPrintPreview. + * @page: the page setup to use + * + * Sets the page setup to use by the #GimpPrintPreview. + **/ +void +gimp_print_preview_set_page_setup (GimpPrintPreview *preview, + GtkPageSetup *page) +{ + gfloat ratio; + + if (preview->page) + g_object_unref (preview->page); + + preview->page = gtk_page_setup_copy (page); + + ratio = (gtk_page_setup_get_paper_width (page, GTK_UNIT_POINTS) / + gtk_page_setup_get_paper_height (page, GTK_UNIT_POINTS)); + + gtk_aspect_frame_set (GTK_ASPECT_FRAME (preview), + 0.5, 0.5, ratio, FALSE); + + gtk_widget_queue_draw (GTK_WIDGET (preview->area)); +} + +/** + * gimp_print_preview_set_image_offsets: + * @preview: a #GimpPrintPreview. + * @offset_x: the X offset + * @offset_y: the Y offset + * + * Sets the offsets of the image/drawable displayed by the #GimpPrintPreview. + * It does not emit the "offsets-changed" signal. + **/ +void +gimp_print_preview_set_image_offsets (GimpPrintPreview *preview, + gdouble offset_x, + gdouble offset_y) +{ + g_return_if_fail (GIMP_IS_PRINT_PREVIEW (preview)); + + preview->image_offset_x = offset_x; + preview->image_offset_y = offset_y; + + gtk_widget_queue_draw (GTK_WIDGET (preview->area)); +} + +/** + * gimp_print_preview_set_image_offsets_max: + * @preview: a #GimpPrintPreview. + * @offset_x_max: the maximum X offset allowed + * @offset_y_max: the maximum Y offset allowed + * + * Sets the maximum offsets of the image/drawable displayed by the #GimpPrintPreview. + * It does not emit the "offsets-changed" signal. + **/ +void +gimp_print_preview_set_image_offsets_max (GimpPrintPreview *preview, + gdouble offset_x_max, + gdouble offset_y_max) +{ + g_return_if_fail (GIMP_IS_PRINT_PREVIEW (preview)); + + preview->image_offset_x_max = offset_x_max; + preview->image_offset_y_max = offset_y_max; +} + +/** + * gimp_print_preview_set_use_full_page: + * @preview: a #GimpPrintPreview. + * @full_page: TRUE to ignore the page margins + * + * If @full_page is TRUE, the page margins are ignored and the full page + * can be used to setup printing. + **/ +void +gimp_print_preview_set_use_full_page (GimpPrintPreview *preview, + gboolean full_page) +{ + g_return_if_fail (GIMP_IS_PRINT_PREVIEW (preview)); + + preview->use_full_page = full_page; + + gtk_widget_queue_draw (GTK_WIDGET (preview->area)); +} + +static gboolean +gimp_print_preview_event (GtkWidget *widget, + GdkEvent *event, + GimpPrintPreview *preview) +{ + static gdouble orig_offset_x = 0.0; + static gdouble orig_offset_y = 0.0; + static gint start_x = 0; + static gint start_y = 0; + + gdouble offset_x; + gdouble offset_y; + gdouble scale; + + switch (event->type) + { + case GDK_BUTTON_PRESS: + gdk_pointer_grab (widget->window, FALSE, + (GDK_BUTTON1_MOTION_MASK | + GDK_BUTTON_RELEASE_MASK), + NULL, NULL, event->button.time); + + orig_offset_x = preview->image_offset_x; + orig_offset_y = preview->image_offset_y; + start_x = event->button.x; + start_y = event->button.y; + break; + + case GDK_MOTION_NOTIFY: + scale = gimp_print_preview_get_scale (preview); + offset_x = (orig_offset_x + (event->motion.x - start_x) / scale); + offset_y = (orig_offset_y + (event->motion.y - start_y) / scale); + + offset_x = CLAMP (offset_x, 0, preview->image_offset_x_max); + offset_y = CLAMP (offset_y, 0, preview->image_offset_y_max); + + if (preview->image_offset_x != offset_x || + preview->image_offset_y != offset_y) + { + preview->image_offset_x = offset_x; + preview->image_offset_y = offset_y; + gtk_widget_queue_draw (GTK_WIDGET (preview->area)); + g_signal_emit (preview, + gimp_print_preview_signals[OFFSETS_CHANGED], 0, + preview->image_offset_x, preview->image_offset_y); + } + break; + + case GDK_BUTTON_RELEASE: + gdk_display_pointer_ungrab (gtk_widget_get_display (widget), + event->button.time); + start_x = start_y = 0; + break; + + default: + break; + } + + return FALSE; +} + +static gboolean +gimp_print_preview_expose_event (GtkWidget *widget, + GdkEventExpose *eevent, + GimpPrintPreview *preview) +{ + gdouble paper_width; + gdouble paper_height; + gdouble left_margin; + gdouble right_margin; + gdouble top_margin; + gdouble bottom_margin; + gdouble scale; + gdouble scale_x; + gdouble scale_y; + cairo_t *cr; + + paper_width = gtk_page_setup_get_paper_width (preview->page, + GTK_UNIT_POINTS); + paper_height = gtk_page_setup_get_paper_height (preview->page, + GTK_UNIT_POINTS); + gimp_print_preview_get_page_margins (preview, + &left_margin, + &right_margin, + &top_margin, + &bottom_margin); + + cr = gdk_cairo_create (widget->window); + + scale = gimp_print_preview_get_scale (preview); + + /* draw background */ + cairo_scale (cr, scale, scale); + gdk_cairo_set_source_color (cr, &(widget->style->white)); + cairo_rectangle (cr, 0, 0, paper_width, paper_height); + cairo_fill (cr); + + /* draw page_margins */ + gdk_cairo_set_source_color (cr, &(widget->style->black)); + cairo_rectangle (cr, + left_margin, + top_margin, + paper_width - left_margin - right_margin, + paper_height - top_margin - bottom_margin); + + cairo_stroke_preserve (cr); + cairo_clip (cr); + cairo_new_path (cr); + + /* draw image */ + cairo_translate (cr, + left_margin + preview->image_offset_x, + top_margin + preview->image_offset_y); + + if (preview->pixbuf == NULL) + { + gint width = MIN (widget->allocation.width, 1024); + gint height = MIN (widget->allocation.height, 1024); + + preview->pixbuf = gimp_drawable_get_thumbnail (preview->drawable_id, + width, height, + GIMP_PIXBUF_KEEP_ALPHA); + } + + scale_x = ((gdouble) gimp_drawable_width (preview->drawable_id) / + gdk_pixbuf_get_width (preview->pixbuf)); + scale_y = ((gdouble) gimp_drawable_height (preview->drawable_id) / + gdk_pixbuf_get_height (preview->pixbuf)); + + if (scale_x < scale_y) + scale_x = scale_y; + else + scale_y = scale_x; + + scale_x = scale_x * 72.0 / preview->image_xres; + scale_y = scale_y * 72.0 / preview->image_yres; + + cairo_scale (cr, scale_x, scale_y); + + gdk_cairo_set_source_pixbuf (cr, preview->pixbuf, 0, 0); + cairo_paint (cr); + + cairo_destroy (cr); + + return FALSE; +} + +static gdouble +gimp_print_preview_get_scale (GimpPrintPreview* preview) +{ + gdouble scale_x; + gdouble scale_y; + + scale_x = ((gdouble) preview->area->allocation.width / + gtk_page_setup_get_paper_width (preview->page, GTK_UNIT_POINTS)); + scale_y = ((gdouble) preview->area->allocation.height / + gtk_page_setup_get_paper_height (preview->page, GTK_UNIT_POINTS)); + + return MIN (scale_x, scale_y); +} + +static void +gimp_print_preview_size_allocate (GtkWidget *widget, + GtkAllocation *allocation, + GimpPrintPreview *preview) +{ + if (preview->pixbuf != NULL) + { + g_object_unref (preview->pixbuf); + preview->pixbuf = NULL; + } +} + +static void +gimp_print_preview_get_page_margins (GimpPrintPreview *preview, + gdouble *left_margin, + gdouble *right_margin, + gdouble *top_margin, + gdouble *bottom_margin) +{ + if (preview->use_full_page) + { + *left_margin = 0.0; + *right_margin = 0.0; + *top_margin = 0.0; + *bottom_margin = 0.0; + } + else + { + *left_margin = gtk_page_setup_get_left_margin (preview->page, + GTK_UNIT_POINTS); + *right_margin = gtk_page_setup_get_right_margin (preview->page, + GTK_UNIT_POINTS); + *top_margin = gtk_page_setup_get_top_margin (preview->page, + GTK_UNIT_POINTS); + *bottom_margin = gtk_page_setup_get_bottom_margin (preview->page, + GTK_UNIT_POINTS); + } +} diff --git a/plug-ins/print/print-preview.h b/plug-ins/print/print-preview.h new file mode 100644 index 0000000000..db65b64f4e --- /dev/null +++ b/plug-ins/print/print-preview.h @@ -0,0 +1,90 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GIMP_PRINT_PREVIEW_H__ +#define __GIMP_PRINT_PREVIEW_H__ + +G_BEGIN_DECLS + + +#define GIMP_TYPE_PRINT_PREVIEW (gimp_print_preview_get_type ()) +#define GIMP_PRINT_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_PRINT_PREVIEW, GimpPrintPreview)) +#define GIMP_PRINT_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_PRINT_PREVIEW, GimpPrintPreviewClass)) +#define GIMP_IS_PRINT_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_PRINT_PREVIEW)) +#define GIMP_IS_PRINT_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_PRINT_PREVIEW)) +#define GIMP_PRINT_PREVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_PRINT_PREVIEW, GimpPrintPreviewClass)) + +typedef struct _GimpPrintPreview GimpPrintPreview; +typedef struct _GimpPrintPreviewClass GimpPrintPreviewClass; + +struct _GimpPrintPreview +{ + GtkAspectFrame parent_instance; + + GtkWidget *area; + GtkPageSetup *page; + GdkPixbuf *pixbuf; + + gint32 drawable_id; + + gdouble image_offset_x; + gdouble image_offset_y; + gdouble image_offset_x_max; + gdouble image_offset_y_max; + gdouble image_xres; + gdouble image_yres; + + gboolean use_full_page; +}; + +struct _GimpPrintPreviewClass +{ + GtkAspectFrameClass parent_class; + + void (* offsets_changed) (GimpPrintPreview *print_preview, + gint offset_x, + gint offset_y); +}; + + +GType gimp_print_preview_get_type (void) G_GNUC_CONST; + +GtkWidget * gimp_print_preview_new (GtkPageSetup *page, + gint32 drawable_id); + +void gimp_print_preview_set_image_dpi (GimpPrintPreview *preview, + gdouble xres, + gdouble yres); + +void gimp_print_preview_set_page_setup (GimpPrintPreview *preview, + GtkPageSetup *page); + +void gimp_print_preview_set_image_offsets (GimpPrintPreview *preview, + gdouble offset_x, + gdouble offset_y); + +void gimp_print_preview_set_image_offsets_max (GimpPrintPreview *preview, + gdouble offset_x_max, + gdouble offset_y_max); + +void gimp_print_preview_set_use_full_page (GimpPrintPreview *preview, + gboolean full_page); + +G_END_DECLS + +#endif /* __GIMP_PRINT_PREVIEW_H__ */ diff --git a/plug-ins/print/print-settings.c b/plug-ins/print/print-settings.c index 68600463ae..2297076ac6 100644 --- a/plug-ins/print/print-settings.c +++ b/plug-ins/print/print-settings.c @@ -17,7 +17,7 @@ */ #define PRINT_SETTINGS_MAJOR_VERSION 0 -#define PRINT_SETTINGS_MINOR_VERSION 2 +#define PRINT_SETTINGS_MINOR_VERSION 3 #include "config.h" @@ -90,6 +90,8 @@ save_print_settings (PrintData *data) g_key_file_set_integer (key_file, "image-setup", "unit", data->unit); g_key_file_set_double (key_file, "image-setup", "x-resolution", data->xres); g_key_file_set_double (key_file, "image-setup", "y-resolution", data->yres); + g_key_file_set_double (key_file, "image-setup", "x-offset", data->offset_x); + g_key_file_set_double (key_file, "image-setup", "y-offset", data->offset_y); save_print_settings_as_parasite (key_file, data->image_id); @@ -341,6 +343,15 @@ load_print_settings_from_key_file (PrintData *data, "image-setup", "y-resolution", NULL); } + if (g_key_file_has_key (key_file, "image-setup", "x-offset", NULL) && + g_key_file_has_key (key_file, "image-setup", "y-offset", NULL)) + { + data->offset_x = g_key_file_get_double (key_file, + "image-setup", "x-offset", NULL); + data->offset_y = g_key_file_get_double (key_file, + "image-setup", "y-offset", NULL); + } + #if 0 /* other settings */ if (g_key_file_has_key (key_file, "other-settings", "show-header", NULL)) diff --git a/plug-ins/print/print.c b/plug-ins/print/print.c index 5581b8297a..88b846bea3 100644 --- a/plug-ins/print/print.c +++ b/plug-ins/print/print.c @@ -156,14 +156,30 @@ print_image (gint32 image_ID, GtkPrintOperation *operation = gtk_print_operation_new (); GError *error = NULL; PrintData *data; + GimpDrawable *drawable; + GimpExportReturn export; + + /* export the image */ + export = gimp_export_image (&image_ID, &drawable_ID, NULL, + GIMP_EXPORT_CAN_HANDLE_RGB | + GIMP_EXPORT_CAN_HANDLE_ALPHA | + GIMP_EXPORT_NEEDS_ALPHA); + + if (export == GIMP_EXPORT_CANCEL) + return FALSE; + + drawable = gimp_drawable_get (drawable_ID); data = g_new0 (PrintData, 1); - data->num_pages = 1; - data->image_id = image_ID; - data->drawable_id = drawable_ID; - data->operation = operation; - data->unit = gimp_get_default_unit (); + data->num_pages = 1; + data->image_id = image_ID; + data->drawable_id = drawable_ID; + data->operation = operation; + data->unit = gimp_get_default_unit (); + data->offset_x = 0; + data->offset_y = 0; + data->use_full_page = FALSE; gimp_image_get_resolution (data->image_id, &data->xres, &data->yres); load_print_settings (data); @@ -217,6 +233,9 @@ print_image (gint32 image_ID, g_object_unref (operation); + gimp_drawable_detach (drawable); + gimp_image_delete (image_ID); + if (error) { GtkWidget *dialog; @@ -247,6 +266,7 @@ begin_print (GtkPrintOperation *operation, data->num_pages = 1; gtk_print_operation_set_n_pages (operation, data->num_pages); + gtk_print_operation_set_use_full_page (operation, data->use_full_page); gimp_progress_init (_("Printing")); } diff --git a/plug-ins/print/print.h b/plug-ins/print/print.h index ff052a3bd3..d74e140db0 100644 --- a/plug-ins/print/print.h +++ b/plug-ins/print/print.h @@ -24,9 +24,11 @@ typedef struct GimpUnit unit; gboolean show_info_header; GtkPrintOperation *operation; - GtkWidget *layout_preview_image; gdouble xres; gdouble yres; + gdouble offset_x; + gdouble offset_y; + gboolean use_full_page; GtkPageOrientation orientation; } PrintData;