Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

View File

@ -0,0 +1,37 @@
if have_print
plugin_name = 'print'
plugin_sources = [
'print-draw-page.c',
'print-page-layout.c',
'print-page-setup.c',
'print-preview.c',
'print-settings.c',
'print-utils.c',
'print.c',
]
if platform_windows
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
'--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
'--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
'--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
],
)
endif
executable(plugin_name,
plugin_sources,
dependencies: libpikaui_dep,
install: true,
install_dir: pikaplugindir / 'plug-ins' / plugin_name,
)
endif

View File

@ -0,0 +1,226 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "print.h"
#include "print-draw-page.h"
#include "libpika/stdplugins-intl.h"
static cairo_surface_t * print_surface_from_drawable (PikaDrawable *drawable,
GError **error);
static void print_draw_crop_marks (GtkPrintContext *context,
gdouble x,
gdouble y,
gdouble w,
gdouble h);
gboolean
print_draw_page (GtkPrintContext *context,
PrintData *data,
GError **error)
{
cairo_t *cr = gtk_print_context_get_cairo_context (context);
cairo_surface_t *surface;
surface = print_surface_from_drawable (data->drawable, error);
if (surface)
{
gint width;
gint height;
gdouble scale_x;
gdouble scale_y;
/* create a white rectangle covering the entire page, just
* to be safe; see bug #777233.
*/
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
cairo_paint (cr);
width = cairo_image_surface_get_width (surface);
height = cairo_image_surface_get_height (surface);
scale_x = gtk_print_context_get_dpi_x (context) / data->xres;
scale_y = gtk_print_context_get_dpi_y (context) / data->yres;
cairo_translate (cr,
data->offset_x / 72.0 * gtk_print_context_get_dpi_x (context),
data->offset_y / 72.0 * gtk_print_context_get_dpi_y (context));
if (data->draw_crop_marks)
print_draw_crop_marks (context,
0, 0, width * scale_x, height * scale_y);
cairo_scale (cr, scale_x, scale_y);
cairo_rectangle (cr, 0, 0, width, height);
cairo_set_source_surface (cr, surface, 0, 0);
cairo_fill (cr);
cairo_surface_destroy (surface);
return TRUE;
}
return FALSE;
}
static cairo_surface_t *
print_surface_from_drawable (PikaDrawable *drawable,
GError **error)
{
GeglBuffer *buffer = pika_drawable_get_buffer (drawable);
const Babl *format;
cairo_surface_t *surface;
cairo_status_t status;
const gint width = pika_drawable_get_width (drawable);
const gint height = pika_drawable_get_height (drawable);
GeglBufferIterator *iter;
guchar *pixels;
gint stride;
guint count = 0;
guint64 done = 0;
if (pika_drawable_has_alpha (drawable))
format = babl_format ("cairo-ARGB32");
else
format = babl_format ("cairo-RGB24");
surface = cairo_image_surface_create (pika_drawable_has_alpha (drawable) ?
CAIRO_FORMAT_ARGB32 :
CAIRO_FORMAT_RGB24,
width, height);
status = cairo_surface_status (surface);
if (status != CAIRO_STATUS_SUCCESS)
{
switch (status)
{
case CAIRO_STATUS_INVALID_SIZE:
g_set_error_literal (error,
PIKA_PLUGIN_PRINT_ERROR,
PIKA_PLUGIN_PRINT_ERROR_FAILED,
_("Cannot handle the size (either width or height) of the image."));
break;
default:
g_set_error (error,
PIKA_PLUGIN_PRINT_ERROR,
PIKA_PLUGIN_PRINT_ERROR_FAILED,
"Cairo error: %s",
cairo_status_to_string (status));
break;
}
return NULL;
}
pixels = cairo_image_surface_get_data (surface);
stride = cairo_image_surface_get_stride (surface);
iter = gegl_buffer_iterator_new (buffer,
GEGL_RECTANGLE (0, 0, width, height), 0,
format,
GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 1);
while (gegl_buffer_iterator_next (iter))
{
const guchar *src = iter->items[0].data;
guchar *dest = pixels + (guint64) iter->items[0].roi.y * stride + iter->items[0].roi.x * 4;
gint y;
for (y = 0; y < iter->items[0].roi.height; y++)
{
memcpy (dest, src, iter->items[0].roi.width * 4);
src += iter->items[0].roi.width * 4;
dest += stride;
}
done += (guint64) iter->items[0].roi.height * iter->items[0].roi.width;
if (count++ % 16 == 0)
pika_progress_update ((gdouble) done / ((gdouble) width * height));
}
g_object_unref (buffer);
cairo_surface_mark_dirty (surface);
pika_progress_update (1.0);
return surface;
}
static void
print_draw_crop_marks (GtkPrintContext *context,
gdouble x,
gdouble y,
gdouble w,
gdouble h)
{
cairo_t *cr = gtk_print_context_get_cairo_context (context);
gdouble len = MIN (gtk_print_context_get_width (context),
gtk_print_context_get_height (context)) / 20.0;
/* upper left */
cairo_move_to (cr, x - len, y);
cairo_line_to (cr, x - len / 5, y);
cairo_move_to (cr, x, y - len);
cairo_line_to (cr, x, y - len / 5);
/* upper right */
cairo_move_to (cr, x + w + len / 5, y);
cairo_line_to (cr, x + w + len, y);
cairo_move_to (cr, x + w, y - len);
cairo_line_to (cr, x + w, y - len / 5);
/* lower left */
cairo_move_to (cr, x - len, y + h);
cairo_line_to (cr, x - len / 5, y + h);
cairo_move_to (cr, x, y + h + len);
cairo_line_to (cr, x, y + h + len / 5);
/* lower right */
cairo_move_to (cr, x + w + len / 5, y + h);
cairo_line_to (cr, x + w + len, y + h);
cairo_move_to (cr, x + w, y + h + len);
cairo_line_to (cr, x + w, y + h + len / 5);
cairo_set_source_rgb (cr, 0.5, 0.5, 0.5);
cairo_set_line_width (cr, 2);
cairo_stroke (cr);
}

View File

@ -0,0 +1,24 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 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 <https://www.gnu.org/licenses/>.
*/
gboolean print_draw_page (GtkPrintContext *context,
PrintData *data,
GError **error);

View File

@ -0,0 +1,949 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "print.h"
#include "print-page-layout.h"
#include "print-preview.h"
#include "libpika/stdplugins-intl.h"
typedef struct
{
PrintData *data;
gint image_width;
gint image_height;
PikaSizeEntry *size_entry;
PikaSizeEntry *resolution_entry;
PikaChainButton *chain;
GtkWidget *center_combo;
GtkWidget *area_label;
GtkWidget *preview;
GtkAdjustment *left_adj;
GtkAdjustment *right_adj;
GtkAdjustment *top_adj;
GtkAdjustment *bottom_adj;
} PrintSizeInfo;
enum
{
BOTTOM,
TOP,
RIGHT,
LEFT,
WIDTH,
HEIGHT
};
static void print_page_setup_notify (GtkPrintOperation *operation);
static void update_custom_widget (GtkPrintOperation *operation,
GtkWidget *custom_widget,
GtkPageSetup *page_setup,
GtkPrintSettings *print_settings);
static GtkWidget * print_size_frame (PrintData *data,
GtkSizeGroup *label_group,
GtkSizeGroup *entry_group);
static GtkWidget * print_offset_frame (PrintData *data,
GtkSizeGroup *label_group,
GtkSizeGroup *entry_group);
static void print_size_info_update_offsets (void);
static void print_size_info_size_changed (GtkWidget *widget);
static void print_size_info_offset_max_changed (GtkAdjustment *adj,
gpointer data);
static void print_size_info_resolution_changed (GtkWidget *widget);
static void print_size_info_unit_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_changed (GtkWidget *widget);
static void print_size_info_center_none (void);
static void print_size_info_use_full_page_toggled
(GtkWidget *widget);
static void print_size_info_set_resolution (PrintSizeInfo *info,
gdouble xres,
gdouble yres);
static void print_size_info_set_page_setup (PrintSizeInfo *info);
static void print_draw_crop_marks_toggled (GtkWidget *widget);
static void print_resolution_load_defaults (PrintSizeInfo *info);
static PrintSizeInfo info;
GtkWidget *
print_page_layout_gui (PrintData *data,
const gchar *help)
{
GtkWidget *main_hbox;
GtkWidget *main_vbox;
GtkWidget *button;
GtkWidget *frame;
GtkPageSetup *setup;
GtkSizeGroup *label_group;
GtkSizeGroup *entry_group;
memset (&info, 0, sizeof (PrintSizeInfo));
info.data = data;
info.image_width = pika_drawable_get_width (data->drawable);
info.image_height = pika_drawable_get_height (data->drawable);
setup = gtk_print_operation_get_default_page_setup (data->operation);
if (! setup)
{
setup = gtk_page_setup_new ();
gtk_print_operation_set_default_page_setup (data->operation, setup);
}
/* main hbox */
main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 12);
/* main vbox */
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_box_pack_start (GTK_BOX (main_hbox), main_vbox, FALSE, FALSE, 0);
gtk_widget_show (main_vbox);
label_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
entry_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
/* size entry area for the image's print size */
frame = print_size_frame (data, label_group, entry_group);
gtk_widget_set_vexpand (frame, FALSE);
gtk_widget_set_valign (frame, GTK_ALIGN_START);
gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
/* offset entry area for the image's offset position */
frame = print_offset_frame (data, label_group, entry_group);
gtk_widget_set_vexpand (frame, FALSE);
gtk_widget_set_valign (frame, GTK_ALIGN_START);
gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
g_object_unref (label_group);
g_object_unref (entry_group);
button = gtk_check_button_new_with_mnemonic (_("Ignore Page _Margins"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
data->use_full_page);
gtk_box_pack_start (GTK_BOX (main_vbox), button, FALSE, FALSE, 0);
g_signal_connect (button, "toggled",
G_CALLBACK (print_size_info_use_full_page_toggled),
NULL);
gtk_widget_show (button);
/* crop marks toggle */
button = gtk_check_button_new_with_mnemonic (_("_Draw Crop Marks"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
data->draw_crop_marks);
gtk_box_pack_start (GTK_BOX (main_vbox), button, FALSE, FALSE, 0);
g_signal_connect (button, "toggled",
G_CALLBACK (print_draw_crop_marks_toggled),
NULL);
gtk_widget_show (button);
/* preview */
frame = pika_frame_new (_("Preview"));
gtk_box_pack_start (GTK_BOX (main_hbox), frame, TRUE, TRUE, 0);
gtk_widget_show (frame);
info.preview = print_preview_new (setup, data->drawable);
print_preview_set_use_full_page (PRINT_PREVIEW (info.preview),
data->use_full_page);
gtk_container_add (GTK_CONTAINER (frame), info.preview);
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);
g_signal_connect_object (data->operation, "notify::default-page-setup",
G_CALLBACK (print_page_setup_notify),
main_hbox, 0);
g_signal_connect_object (data->operation, "update-custom-widget",
G_CALLBACK (update_custom_widget),
main_hbox, 0);
pika_help_connect (main_hbox, pika_standard_help_func, help, NULL, NULL);
return main_hbox;
}
static void
print_page_setup_notify (GtkPrintOperation *operation)
{
GtkPageSetup *setup;
setup = gtk_print_operation_get_default_page_setup (operation);
print_size_info_set_page_setup (&info);
print_preview_set_page_setup (PRINT_PREVIEW (info.preview), setup);
}
static void
update_custom_widget (GtkPrintOperation *operation,
GtkWidget *custom_widget,
GtkPageSetup *page_setup,
GtkPrintSettings *print_settings)
{
gtk_print_operation_set_default_page_setup (operation, page_setup);
}
#define SB_WIDTH 8
static GtkWidget *
print_size_frame (PrintData *data,
GtkSizeGroup *label_group,
GtkSizeGroup *entry_group)
{
GtkWidget *entry;
GtkWidget *height;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *chain;
GtkWidget *frame;
GtkWidget *label;
GtkWidget *button;
GtkAdjustment *adj;
gdouble image_width;
gdouble image_height;
image_width = (info.image_width *
pika_unit_get_factor (data->unit) / data->xres);
image_height = (info.image_height *
pika_unit_get_factor (data->unit) / data->yres);
frame = pika_frame_new (_("Size"));
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
/* the print size entry */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
entry = pika_size_entry_new (1, data->unit, "%p",
FALSE, FALSE, FALSE, SB_WIDTH,
PIKA_SIZE_ENTRY_UPDATE_SIZE);
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
gtk_widget_show (entry);
info.size_entry = PIKA_SIZE_ENTRY (entry);
gtk_grid_set_row_spacing (GTK_GRID (entry), 2);
adj = gtk_adjustment_new (1, 1, 1, 1, 10, 0);
height = pika_spin_button_new (adj, 1, 2);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (height), TRUE);
pika_size_entry_add_field (PIKA_SIZE_ENTRY (entry),
GTK_SPIN_BUTTON (height), NULL);
gtk_grid_attach (GTK_GRID (entry), height, 1, 0, 1, 1);
gtk_widget_show (height);
gtk_size_group_add_widget (entry_group, height);
pika_size_entry_attach_label (PIKA_SIZE_ENTRY (entry),
_("_Width:"), 0, 0, 0.0);
label = pika_size_entry_attach_label (PIKA_SIZE_ENTRY (entry),
_("_Height:"), 1, 0, 0.0);
gtk_size_group_add_widget (label_group, label);
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), 0,
data->xres, FALSE);
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), 1,
data->yres, FALSE);
pika_size_entry_set_value (PIKA_SIZE_ENTRY (entry), 0, image_width);
pika_size_entry_set_value (PIKA_SIZE_ENTRY (entry), 1, image_height);
/* the resolution entry */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
entry = pika_size_entry_new (1, data->image_unit,
_("pixels/%a"),
FALSE, FALSE, FALSE, SB_WIDTH,
PIKA_SIZE_ENTRY_UPDATE_RESOLUTION);
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
gtk_widget_show (entry);
info.resolution_entry = PIKA_SIZE_ENTRY (entry);
gtk_grid_set_row_spacing (GTK_GRID (entry), 2);
adj = gtk_adjustment_new (1, 1, 1, 1, 10, 0);
height = pika_spin_button_new (adj, 1, 2);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (height), TRUE);
pika_size_entry_add_field (PIKA_SIZE_ENTRY (entry),
GTK_SPIN_BUTTON (height), NULL);
gtk_grid_attach (GTK_GRID (entry), height, 1, 0, 1, 1);
gtk_widget_show (height);
gtk_size_group_add_widget (entry_group, height);
label = pika_size_entry_attach_label (PIKA_SIZE_ENTRY (entry),
_("_X resolution:"), 0, 0, 0.0);
gtk_size_group_add_widget (label_group, label);
label = pika_size_entry_attach_label (PIKA_SIZE_ENTRY (entry),
_("_Y resolution:"), 1, 0, 0.0);
gtk_size_group_add_widget (label_group, label);
button = gtk_button_new_with_mnemonic (_("_Load Defaults"));
g_signal_connect_swapped (button, "clicked",
G_CALLBACK (print_resolution_load_defaults),
&info);
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (entry), 0,
PIKA_MIN_RESOLUTION,
PIKA_MAX_RESOLUTION);
pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (entry), 1,
PIKA_MIN_RESOLUTION,
PIKA_MAX_RESOLUTION);
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (entry), 0, data->xres);
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (entry), 1, data->yres);
chain = pika_chain_button_new (PIKA_CHAIN_RIGHT);
if (ABS (data->xres - data->yres) < PIKA_MIN_RESOLUTION)
pika_chain_button_set_active (PIKA_CHAIN_BUTTON (chain), TRUE);
gtk_grid_attach (GTK_GRID (entry), chain, 2, 0, 1, 2);
gtk_widget_show (chain);
info.chain = PIKA_CHAIN_BUTTON (chain);
g_signal_connect (info.resolution_entry, "value-changed",
G_CALLBACK (print_size_info_resolution_changed),
NULL);
g_signal_connect (info.size_entry, "unit-changed",
G_CALLBACK (print_size_info_unit_changed),
NULL);
return frame;
}
static GtkWidget *
print_offset_frame (PrintData *data,
GtkSizeGroup *label_group,
GtkSizeGroup *entry_group)
{
GtkWidget *entry;
GtkWidget *spinner;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *grid;
GtkWidget *frame;
GtkWidget *label;
GtkWidget *combo;
frame = pika_frame_new (_("Position"));
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
/* the offset entry */
entry = GTK_WIDGET (info.size_entry);
grid = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (grid), 2);
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
gtk_box_pack_start (GTK_BOX (vbox), grid, FALSE, FALSE, 0);
gtk_widget_show (grid);
/* left */
info.left_adj = gtk_adjustment_new (1, 1, 1, 1, 10, 0);
spinner = pika_spin_button_new (info.left_adj, 1, 2);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinner), TRUE);
pika_size_entry_add_field (PIKA_SIZE_ENTRY (entry),
GTK_SPIN_BUTTON (spinner), NULL);
gtk_grid_attach (GTK_GRID (grid), spinner, 1, 0, 1, 1);
gtk_widget_show (spinner);
label = gtk_label_new_with_mnemonic (_("_Left:"));
gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinner);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
gtk_size_group_add_widget (label_group, label);
gtk_widget_show (label);
/* right */
info.right_adj = gtk_adjustment_new (1, 1, 1, 1, 10, 0);
spinner = pika_spin_button_new (info.right_adj, 1, 2);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinner), TRUE);
g_signal_connect (info.right_adj, "value-changed",
G_CALLBACK (print_size_info_offset_max_changed),
GINT_TO_POINTER (LEFT));
pika_size_entry_add_field (PIKA_SIZE_ENTRY (entry),
GTK_SPIN_BUTTON (spinner), NULL);
gtk_grid_attach (GTK_GRID (grid), spinner, 3, 0, 1, 1);
gtk_widget_show (spinner);
label = gtk_label_new_with_mnemonic (_("_Right:"));
gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinner);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_grid_attach (GTK_GRID (grid), label, 2, 0, 1, 1);
gtk_widget_show (label);
/* top */
info.top_adj = gtk_adjustment_new (1, 1, 1, 1, 10, 0);
spinner = pika_spin_button_new (info.top_adj, 1, 2);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinner), TRUE);
pika_size_entry_add_field (PIKA_SIZE_ENTRY (entry),
GTK_SPIN_BUTTON (spinner), NULL);
gtk_grid_attach (GTK_GRID (grid), spinner, 1, 1, 1, 1);
gtk_widget_show (spinner);
label = gtk_label_new_with_mnemonic (_("_Top:"));
gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinner);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
gtk_size_group_add_widget (label_group, label);
gtk_widget_show (label);
/* bottom */
info.bottom_adj = gtk_adjustment_new (1, 1, 1, 1, 10, 0);
spinner = pika_spin_button_new (info.bottom_adj, 1, 2);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinner), TRUE);
g_signal_connect (info.bottom_adj, "value-changed",
G_CALLBACK (print_size_info_offset_max_changed),
GINT_TO_POINTER (TOP));
pika_size_entry_add_field (PIKA_SIZE_ENTRY (entry),
GTK_SPIN_BUTTON (spinner), NULL);
gtk_grid_attach (GTK_GRID (grid), spinner, 3, 1, 1, 1);
gtk_widget_show (spinner);
label = gtk_label_new_with_mnemonic (_("_Bottom:"));
gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinner);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_grid_attach (GTK_GRID (grid), label, 2, 1, 1, 1);
gtk_widget_show (label);
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), LEFT, 72.0, FALSE);
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), RIGHT, 72.0, FALSE);
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), TOP, 72.0, FALSE);
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), BOTTOM, 72.0, FALSE);
print_size_info_update_offsets ();
g_signal_connect (info.size_entry, "value-changed",
G_CALLBACK (print_size_info_size_changed),
NULL);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
label = gtk_label_new_with_mnemonic (_("C_enter:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_size_group_add_widget (label_group, label);
gtk_widget_show (label);
/* if and how to center the image on the page */
combo = pika_int_combo_box_new (C_("center-mode", "None"), CENTER_NONE,
_("Horizontally"), CENTER_HORIZONTALLY,
_("Vertically"), CENTER_VERTICALLY,
_("Both"), CENTER_BOTH,
NULL);
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
gtk_widget_show (combo);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
pika_int_combo_box_connect (PIKA_INT_COMBO_BOX (combo),
data->center,
G_CALLBACK (print_size_info_center_changed),
NULL, NULL);
info.center_combo = combo;
g_signal_connect (info.left_adj, "value-changed",
G_CALLBACK (print_size_info_center_none),
NULL);
g_signal_connect (info.right_adj, "value-changed",
G_CALLBACK (print_size_info_center_none),
NULL);
g_signal_connect (info.top_adj, "value-changed",
G_CALLBACK (print_size_info_center_none),
NULL);
g_signal_connect (info.bottom_adj, "value-changed",
G_CALLBACK (print_size_info_center_none),
NULL);
return frame;
}
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
pika_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_none_block (void)
{
g_signal_handlers_block_by_func (info.left_adj,
print_size_info_center_none, NULL);
g_signal_handlers_block_by_func (info.right_adj,
print_size_info_center_none, NULL);
g_signal_handlers_block_by_func (info.top_adj,
print_size_info_center_none, NULL);
g_signal_handlers_block_by_func (info.bottom_adj,
print_size_info_center_none, NULL);
}
static void
print_size_info_center_none_unblock (void)
{
g_signal_handlers_unblock_by_func (info.left_adj,
print_size_info_center_none, NULL);
g_signal_handlers_unblock_by_func (info.right_adj,
print_size_info_center_none, NULL);
g_signal_handlers_unblock_by_func (info.top_adj,
print_size_info_center_none, NULL);
g_signal_handlers_unblock_by_func (info.bottom_adj,
print_size_info_center_none, NULL);
}
static void
print_size_info_update_offsets (void)
{
PrintData *data = info.data;
gdouble offset_x_max;
gdouble offset_y_max;
pika_size_info_get_max_offsets (&offset_x_max, &offset_y_max);
g_signal_handlers_block_by_func (info.size_entry,
print_size_info_size_changed, NULL);
print_size_info_center_none_block ();
pika_size_entry_set_refval_boundaries (info.size_entry, LEFT,
0, offset_x_max);
pika_size_entry_set_refval_boundaries (info.size_entry, RIGHT,
0, offset_x_max);
pika_size_entry_set_refval_boundaries (info.size_entry, TOP,
0, offset_y_max);
pika_size_entry_set_refval_boundaries (info.size_entry, BOTTOM,
0, offset_y_max);
switch (data->center)
{
case CENTER_NONE:
break;
case CENTER_HORIZONTALLY:
data->offset_x = offset_x_max / 2.0;
break;
case CENTER_VERTICALLY:
data->offset_y = offset_y_max / 2.0;
break;
case CENTER_BOTH:
data->offset_x = offset_x_max / 2.0;
data->offset_y = offset_y_max / 2.0;
break;
}
pika_size_entry_set_refval (info.size_entry, LEFT,
data->offset_x);
pika_size_entry_set_refval (info.size_entry, RIGHT,
offset_x_max - data->offset_x);
pika_size_entry_set_refval (info.size_entry, TOP,
info.data->offset_y);
pika_size_entry_set_refval (info.size_entry, BOTTOM,
offset_y_max - data->offset_y);
print_size_info_center_none_unblock ();
g_signal_handlers_unblock_by_func (info.size_entry,
print_size_info_size_changed, NULL);
}
static void
print_size_info_center_changed (GtkWidget *combo)
{
gint value;
if (pika_int_combo_box_get_active (PIKA_INT_COMBO_BOX (combo), &value))
{
info.data->center = value;
print_size_info_update_offsets ();
if (info.preview)
print_preview_set_image_offsets (PRINT_PREVIEW (info.preview),
info.data->offset_x,
info.data->offset_y);
}
}
static void
print_size_info_center_none (void)
{
/* return early if we are called from a unit change */
if (pika_size_entry_get_unit (info.size_entry) != info.data->unit)
return;
info.data->center = CENTER_NONE;
if (info.center_combo)
{
g_signal_handlers_block_by_func (info.center_combo,
print_size_info_center_changed, NULL);
info.data->center = CENTER_NONE;
pika_int_combo_box_set_active (PIKA_INT_COMBO_BOX (info.center_combo),
info.data->center);
g_signal_handlers_unblock_by_func (info.center_combo,
print_size_info_center_changed, NULL);
}
}
static void
print_size_info_preview_offset_changed (GtkWidget *widget,
gdouble offset_x,
gdouble offset_y)
{
print_size_info_center_none ();
info.data->offset_x = offset_x;
info.data->offset_y = offset_y;
print_size_info_update_offsets ();
}
static void
print_size_info_size_changed (GtkWidget *widget)
{
gdouble width;
gdouble height;
gdouble xres;
gdouble yres;
gdouble scale;
scale = pika_unit_get_factor (pika_size_entry_get_unit (info.size_entry));
width = pika_size_entry_get_value (info.size_entry, WIDTH);
height = pika_size_entry_get_value (info.size_entry, HEIGHT);
xres = scale * info.image_width / MAX (0.0001, width);
yres = scale * info.image_height / MAX (0.0001, height);
print_size_info_set_resolution (&info, xres, yres);
info.data->offset_x = pika_size_entry_get_refval (info.size_entry, LEFT);
info.data->offset_y = pika_size_entry_get_refval (info.size_entry, TOP);
print_preview_set_image_offsets (PRINT_PREVIEW (info.preview),
info.data->offset_x,
info.data->offset_y);
}
static void
print_size_info_offset_max_changed (GtkAdjustment *adj,
gpointer data)
{
guint index = GPOINTER_TO_INT (data);
/* return early if we are called from a unit change */
if (pika_size_entry_get_unit (info.size_entry) != info.data->unit)
return;
g_signal_handlers_block_by_func (info.size_entry,
print_size_info_size_changed, NULL);
pika_size_entry_set_value (info.size_entry, index,
gtk_adjustment_get_upper (adj) -
gtk_adjustment_get_value (adj));
g_signal_handlers_unblock_by_func (info.size_entry,
print_size_info_size_changed, NULL);
}
static void
print_size_info_resolution_changed (GtkWidget *widget)
{
PikaSizeEntry *entry = info.resolution_entry;
gdouble xres = pika_size_entry_get_refval (entry, 0);
gdouble yres = pika_size_entry_get_refval (entry, 1);
print_size_info_set_resolution (&info, xres, yres);
}
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);
print_preview_set_use_full_page (PRINT_PREVIEW(info.preview), active);
}
static void
print_size_info_unit_changed (GtkWidget *widget)
{
info.data->unit = pika_size_entry_get_unit (PIKA_SIZE_ENTRY (widget));
print_size_info_set_page_setup (&info);
}
static void
print_size_info_set_resolution (PrintSizeInfo *info,
gdouble xres,
gdouble yres)
{
PrintData *data = info->data;
gdouble offset_x;
gdouble offset_y;
gdouble offset_x_max;
gdouble offset_y_max;
if (info->chain && pika_chain_button_get_active (info->chain))
{
if (xres != data->xres)
yres = xres;
else
xres = yres;
}
data->xres = xres;
data->yres = yres;
g_signal_handlers_block_by_func (info->resolution_entry,
print_size_info_resolution_changed,
NULL);
pika_size_entry_set_refval (info->resolution_entry, 0, xres);
pika_size_entry_set_refval (info->resolution_entry, 1, yres);
g_signal_handlers_unblock_by_func (info->resolution_entry,
print_size_info_resolution_changed,
NULL);
g_signal_handlers_block_by_func (info->size_entry,
print_size_info_size_changed,
NULL);
pika_size_entry_set_value (info->size_entry, WIDTH,
info->image_width *
pika_unit_get_factor (data->unit) / xres);
pika_size_entry_set_value (info->size_entry, HEIGHT,
info->image_height *
pika_unit_get_factor (data->unit) / yres);
g_signal_handlers_unblock_by_func (info->size_entry,
print_size_info_size_changed,
NULL);
pika_size_info_get_max_offsets (&offset_x_max, &offset_y_max);
offset_x = pika_size_entry_get_refval (info->size_entry, LEFT);
offset_y = pika_size_entry_get_refval (info->size_entry, TOP);
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;
print_size_info_update_offsets ();
print_preview_set_image_dpi (PRINT_PREVIEW (info->preview),
data->xres, data->yres);
print_preview_set_image_offsets (PRINT_PREVIEW (info->preview),
data->offset_x, data->offset_y);
print_preview_set_image_offsets_max (PRINT_PREVIEW (info->preview),
offset_x_max, offset_y_max);
}
static void
print_size_info_set_page_setup (PrintSizeInfo *info)
{
PrintData *data = info->data;
gdouble page_width;
gdouble page_height;
gdouble x;
gdouble y;
print_size_info_get_page_dimensions (info,
&page_width, &page_height,
GTK_UNIT_INCH);
page_width *= pika_unit_get_factor (data->unit);
page_height *= pika_unit_get_factor (data->unit);
if (info->area_label)
{
gchar *format;
gchar *text;
format = g_strdup_printf ("%%.%df x %%.%df %s",
pika_unit_get_digits (data->unit),
pika_unit_get_digits (data->unit),
pika_unit_get_plural (data->unit));
text = g_strdup_printf (format, page_width, page_height);
g_free (format);
gtk_label_set_text (GTK_LABEL (info->area_label), text);
g_free (text);
}
x = page_width;
y = page_height;
if (info->chain && pika_chain_button_get_active (info->chain))
{
gdouble ratio_x = page_width / (gdouble) info->image_width;
gdouble ratio_y = page_height / (gdouble) info->image_height;
if (ratio_x < ratio_y)
y = (gdouble) info->image_height * ratio_x;
else
x = (gdouble) info->image_width * ratio_y;
}
pika_size_entry_set_value_boundaries (info->size_entry, WIDTH,
page_width / 100.0, x);
pika_size_entry_set_value_boundaries (info->size_entry, HEIGHT,
page_height / 100.0, y);
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 && pika_chain_button_get_active (info->chain))
{
gdouble max = MAX (x, y);
x = y = max;
}
data->min_xres = x;
data->min_yres = y;
pika_size_entry_set_refval_boundaries (info->resolution_entry, 0,
x, PIKA_MAX_RESOLUTION);
pika_size_entry_set_refval_boundaries (info->resolution_entry, 1,
y, PIKA_MAX_RESOLUTION);
}
static void
print_draw_crop_marks_toggled (GtkWidget *widget)
{
gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
info.data->draw_crop_marks = active;
}
static void
print_resolution_load_defaults (PrintSizeInfo *info)
{
gdouble xres;
gdouble yres;
pika_image_get_resolution (info->data->image, &xres, &yres);
pika_size_entry_set_refval (info->resolution_entry, 0, xres);
pika_size_entry_set_refval (info->resolution_entry, 1, yres);
print_size_info_resolution_changed (GTK_WIDGET (info->resolution_entry));
}

View File

@ -0,0 +1,24 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 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 <https://www.gnu.org/licenses/>.
*/
GtkWidget * print_page_layout_gui (PrintData *data,
const gchar *help_id);

View File

@ -0,0 +1,105 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "print.h"
#include "print-page-setup.h"
#include "print-utils.h"
#define PRINT_PAGE_SETUP_NAME "print-page-setup"
#ifndef EMBED_PAGE_SETUP
void
print_page_setup_dialog (GtkPrintOperation *operation)
{
GtkPrintSettings *settings;
GtkPageSetup *setup;
g_return_if_fail (GTK_IS_PRINT_OPERATION (operation));
setup = gtk_print_operation_get_default_page_setup (operation);
settings = gtk_print_settings_new ();
setup = gtk_print_run_page_setup_dialog (NULL, setup, settings);
g_object_unref (settings);
gtk_print_operation_set_default_page_setup (operation, setup);
}
#endif
void
print_page_setup_load (GtkPrintOperation *operation,
PikaImage *image)
{
GKeyFile *key_file;
g_return_if_fail (GTK_IS_PRINT_OPERATION (operation));
key_file = print_utils_key_file_load_from_parasite (image,
PRINT_PAGE_SETUP_NAME);
if (! key_file)
key_file = print_utils_key_file_load_from_rcfile (PRINT_PAGE_SETUP_NAME);
if (key_file)
{
GtkPageSetup *setup;
setup = gtk_page_setup_new_from_key_file (key_file,
PRINT_PAGE_SETUP_NAME, NULL);
if (setup)
{
gtk_print_operation_set_default_page_setup (operation, setup);
g_object_unref (setup);
}
g_key_file_free (key_file);
}
}
void
print_page_setup_save (GtkPrintOperation *operation,
PikaImage *image)
{
GtkPageSetup *setup;
GKeyFile *key_file;
g_return_if_fail (GTK_IS_PRINT_OPERATION (operation));
key_file = g_key_file_new ();
setup = gtk_print_operation_get_default_page_setup (operation);
gtk_page_setup_to_key_file (setup, key_file, PRINT_PAGE_SETUP_NAME);
print_utils_key_file_save_as_parasite (key_file,
image, PRINT_PAGE_SETUP_NAME);
print_utils_key_file_save_as_rcfile (key_file,
PRINT_PAGE_SETUP_NAME);
g_key_file_free (key_file);
}

View File

@ -0,0 +1,31 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 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 <https://www.gnu.org/licenses/>.
*/
#ifndef EMBED_PAGE_SETUP
void print_page_setup_dialog (GtkPrintOperation *operation);
#endif
void print_page_setup_load (GtkPrintOperation *operation,
PikaImage *image);
void print_page_setup_save (GtkPrintOperation *operation,
PikaImage *image);

View File

@ -0,0 +1,917 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "print-preview.h"
enum
{
OFFSETS_CHANGED,
LAST_SIGNAL
};
#define SIZE_REQUEST 200
struct _PrintPreview
{
GtkEventBox parent_instance;
GdkCursor *cursor;
GtkPageSetup *page;
cairo_surface_t *thumbnail;
gboolean dragging;
gboolean inside;
PikaDrawable *drawable;
gdouble image_offset_x;
gdouble image_offset_y;
gdouble image_offset_x_max;
gdouble image_offset_y_max;
gdouble image_width;
gdouble image_height;
gboolean use_full_page;
/* for mouse drags */
gdouble orig_offset_x;
gdouble orig_offset_y;
gint start_x;
gint start_y;
};
struct _PrintPreviewClass
{
GtkEventBoxClass parent_class;
void (* offsets_changed) (PrintPreview *print_preview,
gint offset_x,
gint offset_y);
};
static void print_preview_finalize (GObject *object);
static void print_preview_realize (GtkWidget *widget);
static void print_preview_unrealize (GtkWidget *widget);
static void print_preview_get_preferred_width (GtkWidget *widget,
gint *minimum_width,
gint *natural_width);
static void print_preview_get_preferred_height (GtkWidget *widget,
gint *minimum_height,
gint *natural_height);
static void print_preview_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gboolean print_preview_draw (GtkWidget *widget,
cairo_t *cr);
static gboolean print_preview_button_press_event (GtkWidget *widget,
GdkEventButton *event);
static gboolean print_preview_button_release_event (GtkWidget *widget,
GdkEventButton *event);
static gboolean print_preview_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event);
static gboolean print_preview_leave_notify_event (GtkWidget *widget,
GdkEventCrossing *event);
static gboolean print_preview_is_inside (PrintPreview *preview,
gdouble x,
gdouble y);
static void print_preview_set_inside (PrintPreview *preview,
gboolean inside);
static gdouble print_preview_get_scale (PrintPreview *preview);
static void print_preview_get_page_size (PrintPreview *preview,
gdouble *paper_width,
gdouble *paper_height);
static void print_preview_get_page_margins (PrintPreview *preview,
gdouble *left_margin,
gdouble *right_margin,
gdouble *top_margin,
gdouble *bottom_margin);
static cairo_surface_t * print_preview_get_thumbnail (PikaDrawable *drawable,
gint width,
gint height);
G_DEFINE_TYPE (PrintPreview, print_preview, GTK_TYPE_EVENT_BOX)
#define parent_class print_preview_parent_class
static guint 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
print_preview_class_init (PrintPreviewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
print_preview_signals[OFFSETS_CHANGED] =
g_signal_new ("offsets-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PrintPreviewClass, offsets_changed),
NULL, NULL,
marshal_VOID__DOUBLE_DOUBLE,
G_TYPE_NONE, 2,
G_TYPE_DOUBLE,
G_TYPE_DOUBLE);
object_class->finalize = print_preview_finalize;
widget_class->realize = print_preview_realize;
widget_class->unrealize = print_preview_unrealize;
widget_class->get_preferred_width = print_preview_get_preferred_width;
widget_class->get_preferred_height = print_preview_get_preferred_height;
widget_class->size_allocate = print_preview_size_allocate;
widget_class->draw = print_preview_draw;
widget_class->button_press_event = print_preview_button_press_event;
widget_class->button_release_event = print_preview_button_release_event;
widget_class->motion_notify_event = print_preview_motion_notify_event;
widget_class->leave_notify_event = print_preview_leave_notify_event;
klass->offsets_changed = NULL;
}
static void
print_preview_init (PrintPreview *preview)
{
gtk_event_box_set_visible_window (GTK_EVENT_BOX (preview), FALSE);
gtk_widget_add_events (GTK_WIDGET (preview),
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK);
}
static void
print_preview_finalize (GObject *object)
{
PrintPreview *preview = PRINT_PREVIEW (object);
if (preview->thumbnail)
{
cairo_surface_destroy (preview->thumbnail);
preview->thumbnail = NULL;
}
if (preview->page)
{
g_object_unref (preview->page);
preview->page = NULL;
}
G_OBJECT_CLASS (print_preview_parent_class)->finalize (object);
}
static void
print_preview_realize (GtkWidget *widget)
{
PrintPreview *preview = PRINT_PREVIEW (widget);
GTK_WIDGET_CLASS (print_preview_parent_class)->realize (widget);
preview->cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
GDK_HAND1);
}
static void
print_preview_unrealize (GtkWidget *widget)
{
PrintPreview *preview = PRINT_PREVIEW (widget);
if (preview->cursor)
g_object_unref (preview->cursor);
GTK_WIDGET_CLASS (print_preview_parent_class)->unrealize (widget);
}
static void
print_preview_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
PrintPreview *preview = PRINT_PREVIEW (widget);
gdouble paper_width;
gdouble paper_height;
gint border;
border = gtk_container_get_border_width (GTK_CONTAINER (widget)) + 1;
print_preview_get_page_size (preview, &paper_width, &paper_height);
if (paper_width > paper_height)
{
requisition->height = SIZE_REQUEST;
requisition->width = paper_width * SIZE_REQUEST / paper_height;
requisition->width = MIN (requisition->width, 2 * SIZE_REQUEST);
}
else
{
requisition->width = SIZE_REQUEST;
requisition->height = paper_height * SIZE_REQUEST / paper_width;
requisition->height = MIN (requisition->height, 2 * SIZE_REQUEST);
}
requisition->width += 2 * border;
requisition->height += 2 * border;
}
static void
print_preview_get_preferred_width (GtkWidget *widget,
gint *minimum_width,
gint *natural_width)
{
GtkRequisition requisition;
print_preview_size_request (widget, &requisition);
*minimum_width = *natural_width = requisition.width;
}
static void
print_preview_get_preferred_height (GtkWidget *widget,
gint *minimum_height,
gint *natural_height)
{
GtkRequisition requisition;
print_preview_size_request (widget, &requisition);
*minimum_height = *natural_height = requisition.height;
}
static void
print_preview_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
PrintPreview *preview = PRINT_PREVIEW (widget);
GTK_WIDGET_CLASS (print_preview_parent_class)->size_allocate (widget,
allocation);
if (preview->thumbnail)
{
cairo_surface_destroy (preview->thumbnail);
preview->thumbnail = NULL;
}
}
static gboolean
print_preview_button_press_event (GtkWidget *widget,
GdkEventButton *event)
{
PrintPreview *preview = PRINT_PREVIEW (widget);
if (event->type == GDK_BUTTON_PRESS && event->button == 1 && preview->inside)
{
GdkDisplay *display = gtk_widget_get_display (widget);
GdkSeat *seat = gdk_display_get_default_seat (display);
GdkCursor *cursor;
cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
GDK_FLEUR);
if (gdk_seat_grab (seat, gdk_event_get_window ((GdkEvent *) event),
GDK_SEAT_CAPABILITY_ALL_POINTING, FALSE,
cursor,
(GdkEvent *) event,
NULL, NULL) == GDK_GRAB_SUCCESS)
{
preview->orig_offset_x = preview->image_offset_x;
preview->orig_offset_y = preview->image_offset_y;
preview->start_x = event->x;
preview->start_y = event->y;
preview->dragging = TRUE;
}
g_object_unref (cursor);
}
return FALSE;
}
static gboolean
print_preview_button_release_event (GtkWidget *widget,
GdkEventButton *event)
{
PrintPreview *preview = PRINT_PREVIEW (widget);
if (preview->dragging)
{
GdkDisplay *display = gtk_widget_get_display (widget);
GdkSeat *seat = gdk_display_get_default_seat (display);
gdk_seat_ungrab (seat);
preview->dragging = FALSE;
print_preview_set_inside (preview,
print_preview_is_inside (preview,
event->x, event->y));
}
return FALSE;
}
static gboolean
print_preview_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event)
{
PrintPreview *preview = PRINT_PREVIEW (widget);
if (preview->dragging)
{
gdouble scale = print_preview_get_scale (preview);
gdouble offset_x;
gdouble offset_y;
offset_x = (preview->orig_offset_x +
(event->x - preview->start_x) / scale);
offset_y = (preview->orig_offset_y +
(event->y - preview->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)
{
print_preview_set_image_offsets (preview, offset_x, offset_y);
g_signal_emit (preview,
print_preview_signals[OFFSETS_CHANGED], 0,
preview->image_offset_x,
preview->image_offset_y);
}
}
else
{
print_preview_set_inside (preview,
print_preview_is_inside (preview,
event->x, event->y));
}
return FALSE;
}
static gboolean
print_preview_leave_notify_event (GtkWidget *widget,
GdkEventCrossing *event)
{
PrintPreview *preview = PRINT_PREVIEW (widget);
if (event->mode == GDK_CROSSING_NORMAL)
print_preview_set_inside (preview, FALSE);
return FALSE;
}
static gboolean
print_preview_draw (GtkWidget *widget,
cairo_t *cr)
{
PrintPreview *preview = PRINT_PREVIEW (widget);
GtkAllocation allocation;
GdkRGBA color;
gdouble paper_width;
gdouble paper_height;
gdouble left_margin;
gdouble right_margin;
gdouble top_margin;
gdouble bottom_margin;
gdouble scale;
gint border;
gtk_widget_get_allocation (widget, &allocation);
border = gtk_container_get_border_width (GTK_CONTAINER (widget)) + 1;
print_preview_get_page_size (preview, &paper_width, &paper_height);
print_preview_get_page_margins (preview,
&left_margin, &right_margin,
&top_margin, &bottom_margin);
scale = print_preview_get_scale (preview);
cairo_translate (cr, border, border);
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
{
gint width = allocation.width - 2 * border;
cairo_translate (cr, width - scale * paper_width, 0);
}
cairo_set_line_width (cr, 1.0);
/* draw page background */
cairo_rectangle (cr, 0, 0, scale * paper_width, scale * paper_height);
color = (GdkRGBA) { 0.0, 0.0, 0.0, 1.0 };
gdk_cairo_set_source_rgba (cr, &color);
cairo_stroke_preserve (cr);
color = (GdkRGBA) { 1.0, 1.0, 1.0, 1.0 };
gdk_cairo_set_source_rgba (cr, &color);
cairo_fill (cr);
/* draw page_margins */
cairo_rectangle (cr,
scale * left_margin,
scale * top_margin,
scale * (paper_width - left_margin - right_margin),
scale * (paper_height - top_margin - bottom_margin));
color = (GdkRGBA) { 0.0, 0.0, 0.0, 0.3 };
gdk_cairo_set_source_rgba (cr, &color);
cairo_stroke (cr);
cairo_translate (cr,
scale * (left_margin + preview->image_offset_x),
scale * (top_margin + preview->image_offset_y));
if (preview->dragging || preview->inside)
{
cairo_rectangle (cr,
0, 0,
scale * preview->image_width,
scale * preview->image_height);
color = (GdkRGBA) { 0.0, 0.0, 0.0, 1.0 };
gdk_cairo_set_source_rgba (cr, &color);
cairo_stroke (cr);
}
if (preview->thumbnail == NULL &&
pika_item_is_valid (PIKA_ITEM (preview->drawable)))
{
preview->thumbnail =
print_preview_get_thumbnail (preview->drawable,
MIN (allocation.width, 1024),
MIN (allocation.height, 1024));
}
if (preview->thumbnail != NULL)
{
gdouble scale_x;
gdouble scale_y;
scale_x = (preview->image_width /
cairo_image_surface_get_width (preview->thumbnail));
scale_y = (preview->image_height /
cairo_image_surface_get_height (preview->thumbnail));
cairo_rectangle (cr, 0, 0, preview->image_width, preview->image_height);
cairo_scale (cr, scale_x * scale, scale_y * scale);
cairo_set_source_surface (cr, preview->thumbnail, 0, 0);
cairo_fill (cr);
}
return FALSE;
}
/**
* print_preview_new:
* @page: page setup
* @drawable: the drawable to print
*
* Creates a new #PrintPreview widget.
*
* Returns: the new #PrintPreview widget.
**/
GtkWidget *
print_preview_new (GtkPageSetup *page,
PikaDrawable *drawable)
{
PrintPreview *preview;
g_return_val_if_fail (GTK_IS_PAGE_SETUP (page), NULL);
preview = g_object_new (PRINT_TYPE_PREVIEW, NULL);
preview->drawable = drawable;
print_preview_set_page_setup (preview, page);
return GTK_WIDGET (preview);
}
/**
* print_preview_set_image_dpi:
* @preview: a #PrintPreview.
* @xres: the X resolution
* @yres: the Y resolution
*
* Sets the resolution of the image/drawable displayed by the
* #PrintPreview.
**/
void
print_preview_set_image_dpi (PrintPreview *preview,
gdouble xres,
gdouble yres)
{
gdouble width;
gdouble height;
g_return_if_fail (PRINT_IS_PREVIEW (preview));
g_return_if_fail (xres > 0.0 && yres > 0.0);
width = pika_drawable_get_width (preview->drawable) * 72.0 / xres;
height = pika_drawable_get_height (preview->drawable) * 72.0 / yres;
if (width != preview->image_width || height != preview->image_height)
{
preview->image_width = width;
preview->image_height = height;
gtk_widget_queue_draw (GTK_WIDGET (preview));
}
}
/**
* print_preview_set_page_setup:
* @preview: a #PrintPreview.
* @page: the page setup to use
*
* Sets the page setup to use by the #PrintPreview.
**/
void
print_preview_set_page_setup (PrintPreview *preview,
GtkPageSetup *page)
{
g_return_if_fail (PRINT_IS_PREVIEW (preview));
g_return_if_fail (GTK_IS_PAGE_SETUP (page));
if (preview->page)
g_object_unref (preview->page);
preview->page = gtk_page_setup_copy (page);
gtk_widget_queue_resize (GTK_WIDGET (preview));
}
/**
* print_preview_set_image_offsets:
* @preview: a #PrintPreview.
* @offset_x: the X offset
* @offset_y: the Y offset
*
* Sets the offsets of the image/drawable displayed by the #PrintPreview.
* It does not emit the "offsets-changed" signal.
**/
void
print_preview_set_image_offsets (PrintPreview *preview,
gdouble offset_x,
gdouble offset_y)
{
g_return_if_fail (PRINT_IS_PREVIEW (preview));
preview->image_offset_x = offset_x;
preview->image_offset_y = offset_y;
gtk_widget_queue_draw (GTK_WIDGET (preview));
}
/**
* print_preview_set_image_offsets_max:
* @preview: a #PrintPreview.
* @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
* #PrintPreview. It does not emit the "offsets-changed" signal.
**/
void
print_preview_set_image_offsets_max (PrintPreview *preview,
gdouble offset_x_max,
gdouble offset_y_max)
{
g_return_if_fail (PRINT_IS_PREVIEW (preview));
preview->image_offset_x_max = offset_x_max;
preview->image_offset_y_max = offset_y_max;
gtk_widget_queue_draw (GTK_WIDGET (preview));
}
/**
* print_preview_set_use_full_page:
* @preview: a #PrintPreview.
* @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
print_preview_set_use_full_page (PrintPreview *preview,
gboolean full_page)
{
g_return_if_fail (PRINT_IS_PREVIEW (preview));
preview->use_full_page = full_page;
gtk_widget_queue_draw (GTK_WIDGET (preview));
}
static gboolean
print_preview_is_inside (PrintPreview *preview,
gdouble x,
gdouble y)
{
GtkWidget *widget = GTK_WIDGET (preview);
GtkAllocation allocation;
gdouble left_margin;
gdouble right_margin;
gdouble top_margin;
gdouble bottom_margin;
gdouble scale;
gint border;
gtk_widget_get_allocation (widget, &allocation);
border = gtk_container_get_border_width (GTK_CONTAINER (widget)) + 1;
x -= border;
scale = print_preview_get_scale (preview);
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
{
gdouble paper_width;
gdouble paper_height;
gint width = allocation.width - 2 * border;
print_preview_get_page_size (preview, &paper_width, &paper_height);
x -= width - scale * paper_width;
}
print_preview_get_page_margins (preview,
&left_margin, &right_margin,
&top_margin, &bottom_margin);
x = x / scale - left_margin;
y = y / scale - top_margin;
return (x > preview->image_offset_x &&
x < preview->image_offset_x + preview->image_width &&
y > preview->image_offset_y &&
y < preview->image_offset_y + preview->image_height);
}
static void
print_preview_set_inside (PrintPreview *preview,
gboolean inside)
{
if (inside != preview->inside)
{
GtkWidget *widget = GTK_WIDGET (preview);
preview->inside = inside;
if (gtk_widget_is_drawable (widget))
gdk_window_set_cursor (gtk_widget_get_window (widget),
inside ? preview->cursor : NULL);
gtk_widget_queue_draw (widget);
}
}
static gdouble
print_preview_get_scale (PrintPreview *preview)
{
GtkWidget *widget = GTK_WIDGET (preview);
GtkAllocation allocation;
gdouble paper_width;
gdouble paper_height;
gdouble scale_x;
gdouble scale_y;
gint border;
gtk_widget_get_allocation (widget, &allocation);
border = gtk_container_get_border_width (GTK_CONTAINER (widget)) + 1;
print_preview_get_page_size (preview, &paper_width, &paper_height);
scale_x = (gdouble) (allocation.width - 2 * border) / paper_width;
scale_y = (gdouble) (allocation.height - 2 * border) / paper_height;
return MIN (scale_x, scale_y);
}
static void
print_preview_get_page_size (PrintPreview *preview,
gdouble *paper_width,
gdouble *paper_height)
{
*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);
}
static void
print_preview_get_page_margins (PrintPreview *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);
}
}
/* This thumbnail code should eventually end up in libpikaui. */
static cairo_surface_t *
print_preview_get_thumbnail (PikaDrawable *drawable,
gint width,
gint height)
{
cairo_surface_t *surface;
cairo_format_t format;
GBytes *data;
guchar *dest;
const guchar *src;
gint src_stride;
gint dest_stride;
gint y;
gint bpp;
g_return_val_if_fail (width > 0 && width <= 1024, NULL);
g_return_val_if_fail (height > 0 && height <= 1024, NULL);
data = pika_drawable_get_thumbnail_data (drawable,
width, height,
&width, &height, &bpp);
switch (bpp)
{
case 1:
case 3:
format = CAIRO_FORMAT_RGB24;
break;
case 2:
case 4:
format = CAIRO_FORMAT_ARGB32;
break;
default:
g_assert_not_reached ();
break;
}
surface = cairo_image_surface_create (format, width, height);
src = g_bytes_get_data (data, NULL);
src_stride = width * bpp;
dest = cairo_image_surface_get_data (surface);
dest_stride = cairo_image_surface_get_stride (surface);
for (y = 0; y < height; y++)
{
const guchar *s = src;
guchar *d = dest;
gint w = width;
switch (bpp)
{
case 1:
while (w--)
{
PIKA_CAIRO_RGB24_SET_PIXEL (d, s[0], s[0], s[0]);
s += 1;
d += 4;
}
break;
case 2:
while (w--)
{
PIKA_CAIRO_ARGB32_SET_PIXEL (d, s[0], s[0], s[0], s[1]);
s += 2;
d += 4;
}
break;
case 3:
while (w--)
{
PIKA_CAIRO_RGB24_SET_PIXEL (d, s[0], s[1], s[2]);
s += 3;
d += 4;
}
break;
case 4:
while (w--)
{
PIKA_CAIRO_ARGB32_SET_PIXEL (d, s[0], s[1], s[2], s[3]);
s += 4;
d += 4;
}
break;
}
src += src_stride;
dest += dest_stride;
}
g_bytes_unref (data);
cairo_surface_mark_dirty (surface);
return surface;
}

View File

@ -0,0 +1,64 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 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 <https://www.gnu.org/licenses/>.
*/
#ifndef __PRINT_PREVIEW_H__
#define __PRINT_PREVIEW_H__
G_BEGIN_DECLS
#define PRINT_TYPE_PREVIEW (print_preview_get_type ())
#define PRINT_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PRINT_TYPE_PREVIEW, PrintPreview))
#define PRINT_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PRINT_TYPE_PREVIEW, PrintPreviewClass))
#define PRINT_IS_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PRINT_TYPE_PREVIEW))
#define PRINT_IS_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PRINT_TYPE_PREVIEW))
#define PRINT_PREVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PRINT_TYPE_PREVIEW, PrintPreviewClass))
typedef struct _PrintPreview PrintPreview;
typedef struct _PrintPreviewClass PrintPreviewClass;
GType print_preview_get_type (void) G_GNUC_CONST;
GtkWidget * print_preview_new (GtkPageSetup *page,
PikaDrawable *drawable);
void print_preview_set_image_dpi (PrintPreview *preview,
gdouble xres,
gdouble yres);
void print_preview_set_page_setup (PrintPreview *preview,
GtkPageSetup *page);
void print_preview_set_image_offsets (PrintPreview *preview,
gdouble offset_x,
gdouble offset_y);
void print_preview_set_image_offsets_max (PrintPreview *preview,
gdouble offset_x_max,
gdouble offset_y_max);
void print_preview_set_use_full_page (PrintPreview *preview,
gboolean full_page);
G_END_DECLS
#endif /* __PRINT_PREVIEW_H__ */

View File

@ -0,0 +1,324 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "print.h"
#include "print-settings.h"
#include "print-utils.h"
#define PRINT_SETTINGS_MAJOR_VERSION 0
#define PRINT_SETTINGS_MINOR_VERSION 4
#define PRINT_SETTINGS_NAME "print-settings"
static GKeyFile * print_settings_key_file_from_settings (PrintData *data);
static void print_settings_add_to_key_file (const gchar *key,
const gchar *value,
gpointer data);
static GKeyFile * print_settings_key_file_from_resource_file (void);
static GKeyFile * print_settings_key_file_from_parasite (PikaImage *image);
static gboolean print_settings_load_from_key_file (PrintData *data,
GKeyFile *key_file);
static gboolean print_settings_check_version (GKeyFile *key_file);
/*
* set GtkPrintSettings from the contents of a "print-settings"
* image parasite, or, if none exists, from a resource
* file of the same name
*/
gboolean
print_settings_load (PrintData *data)
{
GKeyFile *key_file = print_settings_key_file_from_parasite (data->image);
if (! key_file)
key_file = print_settings_key_file_from_resource_file ();
if (key_file)
{
print_settings_load_from_key_file (data, key_file);
g_key_file_free (key_file);
return TRUE;
}
return FALSE;
}
/*
* save all settings as a resource file "print-settings"
* and as an image parasite
*/
void
print_settings_save (PrintData *data)
{
GKeyFile *key_file = print_settings_key_file_from_settings (data);
/* image setup */
if (pika_image_is_valid (data->image))
{
gdouble xres;
gdouble yres;
pika_image_get_resolution (data->image, &xres, &yres);
g_key_file_set_integer (key_file, "image-setup",
"unit", data->unit);
/* Do not save the print resolution when it is the expected image
* resolution so that changing it (i.e. in "print size" dialog)
* is not overridden by any previous prints.
*/
if ((data->min_xres <= xres && ABS (xres - data->xres) > 0.1) ||
(data->min_yres <= yres && ABS (yres - data->yres) > 0.1) ||
(data->min_xres > xres && ABS (data->min_xres - data->xres) > 0.1) ||
(data->min_yres > yres && ABS (data->min_yres - data->yres) > 0.1))
{
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);
g_key_file_set_integer (key_file, "image-setup",
"center-mode", data->center);
g_key_file_set_boolean (key_file, "image-setup",
"use-full-page", data->use_full_page);
g_key_file_set_boolean (key_file, "image-setup",
"crop-marks", data->draw_crop_marks);
print_utils_key_file_save_as_parasite (key_file,
data->image,
PRINT_SETTINGS_NAME);
}
/* some settings shouldn't be made persistent on a global level,
* so they are only stored in the image, not in the rcfile
*/
g_key_file_remove_key (key_file, "image-setup", "x-resolution", NULL);
g_key_file_remove_key (key_file, "image-setup", "y-resolution", NULL);
g_key_file_remove_key (key_file, "image-setup", "x-offset", NULL);
g_key_file_remove_key (key_file, "image-setup", "y-offset", NULL);
g_key_file_remove_key (key_file, PRINT_SETTINGS_NAME, "n-copies", NULL);
print_utils_key_file_save_as_rcfile (key_file, PRINT_SETTINGS_NAME);
g_key_file_free (key_file);
}
/*
* serialize print settings into a GKeyFile
*/
static GKeyFile *
print_settings_key_file_from_settings (PrintData *data)
{
GtkPrintOperation *operation = data->operation;
GtkPrintSettings *settings;
GKeyFile *key_file = g_key_file_new ();
/* put version information into the file */
g_key_file_set_integer (key_file, "meta", "major-version",
PRINT_SETTINGS_MAJOR_VERSION);
g_key_file_set_integer (key_file, "meta", "minor-version",
PRINT_SETTINGS_MINOR_VERSION);
/* save the contents of the GtkPrintSettings for the operation */
settings = gtk_print_operation_get_print_settings (operation);
if (settings)
gtk_print_settings_foreach (settings,
print_settings_add_to_key_file, key_file);
return key_file;
}
/*
* callback used in gtk_print_settings_foreach loop
*/
static void
print_settings_add_to_key_file (const gchar *key,
const gchar *value,
gpointer data)
{
GKeyFile *key_file = data;
g_key_file_set_value (key_file, PRINT_SETTINGS_NAME, key, value);
}
/*
* deserialize a "print-settings" resource file into a GKeyFile
*/
static GKeyFile *
print_settings_key_file_from_resource_file (void)
{
GKeyFile *key_file;
key_file = print_utils_key_file_load_from_rcfile (PRINT_SETTINGS_NAME);
if (key_file && ! print_settings_check_version (key_file))
{
g_key_file_free (key_file);
return NULL;
}
return key_file;
}
/* load information from an image parasite called "print-settings"
* return a GKeyFile containing the information if a valid parasite is found,
* NULL otherwise
*/
static GKeyFile *
print_settings_key_file_from_parasite (PikaImage *image)
{
GKeyFile *key_file;
key_file = print_utils_key_file_load_from_parasite (image,
PRINT_SETTINGS_NAME);
if (key_file && ! print_settings_check_version (key_file))
{
g_key_file_free (key_file);
return NULL;
}
return key_file;
}
static gboolean
print_settings_load_from_key_file (PrintData *data,
GKeyFile *key_file)
{
GtkPrintOperation *operation = data->operation;
GtkPrintSettings *settings;
gchar **keys;
gsize n_keys;
gint i;
settings = gtk_print_operation_get_print_settings (operation);
if (! settings)
settings = gtk_print_settings_new ();
keys = g_key_file_get_keys (key_file, PRINT_SETTINGS_NAME, &n_keys, NULL);
if (! keys)
return FALSE;
for (i = 0; i < n_keys; i++)
{
gchar *value;
value = g_key_file_get_value (key_file,
PRINT_SETTINGS_NAME, keys[i], NULL);
if (value)
{
gtk_print_settings_set (settings, keys[i], value);
g_free (value);
}
}
g_strfreev (keys);
if (g_key_file_has_key (key_file, "image-setup", "unit", NULL))
{
data->unit = g_key_file_get_integer (key_file, "image-setup",
"unit", NULL);
}
if (g_key_file_has_key (key_file, "image-setup", "x-resolution", NULL) &&
g_key_file_has_key (key_file, "image-setup", "y-resolution", NULL))
{
data->xres = g_key_file_get_double (key_file, "image-setup",
"x-resolution", NULL);
data->yres = g_key_file_get_double (key_file, "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 (g_key_file_has_key (key_file, "image-setup", "center-mode", NULL))
{
data->center = g_key_file_get_integer (key_file, "image-setup",
"center-mode", NULL);
}
if (g_key_file_has_key (key_file, "image-setup", "use-full-page", NULL))
{
data->use_full_page = g_key_file_get_boolean (key_file, "image-setup",
"use-full-page", NULL);
}
if (g_key_file_has_key (key_file, "image-setup", "crop-marks", NULL))
{
data->draw_crop_marks = g_key_file_get_boolean (key_file, "image-setup",
"crop-marks", NULL);
}
gtk_print_operation_set_print_settings (operation, settings);
return TRUE;
}
static gboolean
print_settings_check_version (GKeyFile *key_file)
{
gint major_version;
gint minor_version;
if (! g_key_file_has_group (key_file, "meta"))
return FALSE;
major_version = g_key_file_get_integer (key_file,
"meta", "major-version", NULL);
if (major_version != PRINT_SETTINGS_MAJOR_VERSION)
return FALSE;
minor_version = g_key_file_get_integer (key_file,
"meta", "minor-version", NULL);
if (minor_version != PRINT_SETTINGS_MINOR_VERSION)
return FALSE;
return TRUE;
}

View File

@ -0,0 +1,23 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 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 <https://www.gnu.org/licenses/>.
*/
gboolean print_settings_load (PrintData *data);
void print_settings_save (PrintData *data);

View File

@ -0,0 +1,151 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <libpika/pika.h>
#include "print-utils.h"
GKeyFile *
print_utils_key_file_load_from_rcfile (const gchar *basename)
{
GKeyFile *key_file;
gchar *filename;
g_return_val_if_fail (basename != NULL, NULL);
filename = g_build_filename (pika_directory (), basename, NULL);
key_file = g_key_file_new ();
if (! g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL))
{
g_key_file_free (key_file);
key_file = NULL;
}
g_free (filename);
return key_file;
}
GKeyFile *
print_utils_key_file_load_from_parasite (PikaImage *image,
const gchar *parasite_name)
{
PikaParasite *parasite;
GKeyFile *key_file;
GError *error = NULL;
const gchar *parasite_data;
guint32 parasite_size;
g_return_val_if_fail (parasite_name != NULL, NULL);
parasite = pika_image_get_parasite (image, parasite_name);
if (! parasite)
return NULL;
key_file = g_key_file_new ();
parasite_data = pika_parasite_get_data (parasite, &parasite_size);
if (! g_key_file_load_from_data (key_file, parasite_data, parasite_size,
G_KEY_FILE_NONE, &error))
{
g_key_file_free (key_file);
pika_parasite_free (parasite);
g_warning ("Unable to create key file from image parasite '%s': %s",
parasite_name, error->message);
g_error_free (error);
return NULL;
}
pika_parasite_free (parasite);
return key_file;
}
void
print_utils_key_file_save_as_rcfile (GKeyFile *key_file,
const gchar *basename)
{
gchar *filename;
gchar *contents;
gsize length;
GError *error = NULL;
g_return_if_fail (basename != NULL);
contents = g_key_file_to_data (key_file, &length, &error);
if (! contents)
{
g_warning ("Unable to get contents of key file for '%s': %s",
basename, error->message);
g_error_free (error);
return;
}
filename = g_build_filename (pika_directory (), basename, NULL);
if (! g_file_set_contents (filename, contents, length, &error))
{
g_warning ("Unable to write settings to '%s': %s",
pika_filename_to_utf8 (filename), error->message);
g_error_free (error);
}
g_free (filename);
g_free (contents);
}
void
print_utils_key_file_save_as_parasite (GKeyFile *key_file,
PikaImage *image,
const gchar *parasite_name)
{
PikaParasite *parasite;
gchar *contents;
gsize length;
GError *error = NULL;
g_return_if_fail (parasite_name != NULL);
contents = g_key_file_to_data (key_file, &length, &error);
if (! contents)
{
g_warning ("Unable to get contents of key file for parasite '%s': %s",
parasite_name, error->message);
g_error_free (error);
return;
}
parasite = pika_parasite_new (parasite_name, 0, length, contents);
g_free (contents);
pika_image_attach_parasite (image, parasite);
pika_parasite_free (parasite);
}

View File

@ -0,0 +1,30 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 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 <https://www.gnu.org/licenses/>.
*/
GKeyFile * print_utils_key_file_load_from_rcfile (const gchar *basename);
GKeyFile * print_utils_key_file_load_from_parasite (PikaImage *image,
const gchar *parasite_name);
void print_utils_key_file_save_as_rcfile (GKeyFile *key_file,
const gchar *basename);
void print_utils_key_file_save_as_parasite (GKeyFile *key_file,
PikaImage *image,
const gchar *parasite_name);

562
plug-ins/print/print.c Normal file
View File

@ -0,0 +1,562 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "print.h"
#include "print-settings.h"
#include "print-page-layout.h"
#include "print-page-setup.h"
#include "print-draw-page.h"
#include "libpika/stdplugins-intl.h"
#define PLUG_IN_BINARY "print"
#define PLUG_IN_ROLE "pika-print"
#define PRINT_PROC_NAME "file-print-gtk"
#ifndef EMBED_PAGE_SETUP
#define PAGE_SETUP_PROC_NAME "file-print-gtk-page-setup"
#define PRINT_TEMP_PROC_NAME "file-print-gtk-page-setup-notify-temp"
#endif
G_DEFINE_QUARK (pika-plugin-print-error-quark, pika_plugin_print_error)
typedef struct _Print Print;
typedef struct _PrintClass PrintClass;
struct _Print
{
PikaPlugIn parent_instance;
};
struct _PrintClass
{
PikaPlugInClass parent_class;
};
#define PRINT_TYPE (print_get_type ())
#define PRINT (obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PRINT_TYPE, Print))
GType print_get_type (void) G_GNUC_CONST;
static GList * print_query_procedures (PikaPlugIn *plug_in);
static PikaProcedure * print_create_procedure (PikaPlugIn *plug_in,
const gchar *name);
static PikaValueArray * print_run (PikaProcedure *procedure,
PikaRunMode run_mode,
PikaImage *image,
gint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args,
gpointer run_data);
static PikaPDBStatusType print_image (PikaImage *image,
gboolean interactive,
GError **error);
#ifndef EMBED_PAGE_SETUP
static PikaPDBStatusType page_setup (PikaImage *image);
#endif
static void print_show_error (const gchar *message);
static void print_operation_set_name (GtkPrintOperation *operation,
PikaImage *image);
static void begin_print (GtkPrintOperation *operation,
GtkPrintContext *context,
PrintData *data);
static void end_print (GtkPrintOperation *operation,
GtkPrintContext *context,
PikaLayer **layer);
static void draw_page (GtkPrintOperation *print,
GtkPrintContext *context,
gint page_nr,
PrintData *data);
static GtkWidget * create_custom_widget (GtkPrintOperation *operation,
PrintData *data);
#ifndef EMBED_PAGE_SETUP
static gchar * print_temp_proc_name (PikaImage *image);
static gchar * print_temp_proc_install (PikaImage *image);
/* Keep a reference to the current GtkPrintOperation
* for access by the temporary procedure.
*/
static GtkPrintOperation *print_operation = NULL;
#endif
G_DEFINE_TYPE (Print, print, PIKA_TYPE_PLUG_IN)
PIKA_MAIN (PRINT_TYPE)
DEFINE_STD_SET_I18N
static void
print_class_init (PrintClass *klass)
{
PikaPlugInClass *plug_in_class = PIKA_PLUG_IN_CLASS (klass);
plug_in_class->query_procedures = print_query_procedures;
plug_in_class->create_procedure = print_create_procedure;
plug_in_class->set_i18n = STD_SET_I18N;
}
static void
print_init (Print *print)
{
}
static GList *
print_query_procedures (PikaPlugIn *plug_in)
{
GList *list = NULL;
list = g_list_append (list, g_strdup (PRINT_PROC_NAME));
#ifndef EMBED_PAGE_SETUP
list = g_list_append (list, g_strdup (PAGE_SETUP_PROC_NAME));
#endif
return list;
}
static PikaProcedure *
print_create_procedure (PikaPlugIn *plug_in,
const gchar *name)
{
PikaProcedure *procedure = NULL;
if (! strcmp (name, PRINT_PROC_NAME))
{
procedure = pika_image_procedure_new (plug_in, name,
PIKA_PDB_PROC_TYPE_PLUGIN,
print_run, NULL, NULL);
pika_procedure_set_image_types (procedure, "*");
pika_procedure_set_sensitivity_mask (procedure,
PIKA_PROCEDURE_SENSITIVE_DRAWABLE |
PIKA_PROCEDURE_SENSITIVE_DRAWABLES |
PIKA_PROCEDURE_SENSITIVE_NO_DRAWABLES);
pika_procedure_set_menu_label (procedure, _("_Print..."));
pika_procedure_set_icon_name (procedure, PIKA_ICON_DOCUMENT_PRINT);
pika_procedure_add_menu_path (procedure, "<Image>/File/[Send]");
pika_procedure_set_documentation (procedure,
_("Print the image"),
"Print the image using the "
"GTK+ Print API.",
name);
pika_procedure_set_attribution (procedure,
"Bill Skaggs, Sven Neumann, Stefan Röllin",
"Bill Skaggs <weskaggs@primate.ucdavis.edu>",
"2006 - 2008");
}
#ifndef EMBED_PAGE_SETUP
else if (! strcmp (name, PAGE_SETUP_PROC_NAME))
{
procedure = pika_image_procedure_new (plug_in, name,
PIKA_PDB_PROC_TYPE_PLUGIN,
print_run, NULL, NULL);
pika_procedure_set_image_types (procedure, "*");
pika_procedure_set_menu_label (procedure, _("Page Set_up..."));
pika_procedure_set_icon_name (procedure, PIKA_ICON_DOCUMENT_PAGE_SETUP);
pika_procedure_add_menu_path (procedure, "<Image>/File/[Send]");
pika_procedure_set_documentation (procedure,
_("Adjust page size and orientation "
"for printing"),
"Adjust page size and orientation "
"for printing the image using the "
"GTK+ Print API.",
name);
pika_procedure_set_attribution (procedure,
"Bill Skaggs, Sven Neumann, Stefan Röllin",
"Sven Neumann <sven@gimp.org>",
"2008");
}
#endif
return procedure;
}
static PikaValueArray *
print_run (PikaProcedure *procedure,
PikaRunMode run_mode,
PikaImage *image,
gint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args,
gpointer run_data)
{
PikaPDBStatusType status;
GError *error = NULL;
gegl_init (NULL, NULL);
if (strcmp (pika_procedure_get_name (procedure),
PRINT_PROC_NAME) == 0)
{
status = print_image (image, run_mode == PIKA_RUN_INTERACTIVE, &error);
if (error && run_mode == PIKA_RUN_INTERACTIVE)
{
print_show_error (error->message);
}
}
#ifndef EMBED_PAGE_SETUP
else if (strcmp (pika_procedure_get_name (procedure),
PAGE_SETUP_PROC_NAME) == 0)
{
if (run_mode == PIKA_RUN_INTERACTIVE)
{
status = page_setup (image);
}
else
{
status = PIKA_PDB_CALLING_ERROR;
}
}
#endif
else
{
status = PIKA_PDB_CALLING_ERROR;
}
return pika_procedure_new_return_values (procedure, status, error);
}
static PikaPDBStatusType
print_image (PikaImage *image,
gboolean interactive,
GError **error)
{
GtkPrintOperation *operation;
GtkPrintOperationResult result;
PikaLayer *layer;
PrintData data;
#ifndef EMBED_PAGE_SETUP
gchar *temp_proc;
#endif
/* create a print layer from the projection */
layer = pika_layer_new_from_visible (image, image, PRINT_PROC_NAME);
operation = gtk_print_operation_new ();
gtk_print_operation_set_n_pages (operation, 1);
print_operation_set_name (operation, image);
print_page_setup_load (operation, image);
/* fill in the PrintData struct */
data.image = image;
data.drawable = PIKA_DRAWABLE (layer);
data.unit = pika_get_default_unit ();
data.image_unit = pika_image_get_unit (image);
data.offset_x = 0;
data.offset_y = 0;
data.center = CENTER_BOTH;
data.use_full_page = FALSE;
data.draw_crop_marks = FALSE;
data.operation = operation;
pika_image_get_resolution (image, &data.xres, &data.yres);
print_settings_load (&data);
gtk_print_operation_set_unit (operation, GTK_UNIT_PIXEL);
g_signal_connect (operation, "begin-print",
G_CALLBACK (begin_print),
&data);
g_signal_connect (operation, "draw-page",
G_CALLBACK (draw_page),
&data);
g_signal_connect (operation, "end-print",
G_CALLBACK (end_print),
&layer);
#ifndef EMBED_PAGE_SETUP
print_operation = operation;
temp_proc = print_temp_proc_install (image);
pika_plug_in_extension_enable (pika_get_plug_in ());
#endif
if (interactive)
{
pika_ui_init (PLUG_IN_BINARY);
g_signal_connect_swapped (operation, "end-print",
G_CALLBACK (print_settings_save),
&data);
g_signal_connect (operation, "create-custom-widget",
G_CALLBACK (create_custom_widget),
&data);
gtk_print_operation_set_custom_tab_label (operation, _("Image Settings"));
#ifdef EMBED_PAGE_SETUP
gtk_print_operation_set_embed_page_setup (operation, TRUE);
#endif
result = gtk_print_operation_run (operation,
GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
NULL, error);
if (result == GTK_PRINT_OPERATION_RESULT_APPLY ||
result == GTK_PRINT_OPERATION_RESULT_IN_PROGRESS)
{
print_page_setup_save (operation, image);
}
}
else
{
result = gtk_print_operation_run (operation,
GTK_PRINT_OPERATION_ACTION_PRINT,
NULL, error);
}
#ifndef EMBED_PAGE_SETUP
pika_plug_in_remove_temp_procedure (pika_get_plug_in (), temp_proc);
g_free (temp_proc);
print_operation = NULL;
#endif
g_object_unref (operation);
if (pika_item_is_valid (PIKA_ITEM (layer)))
pika_item_delete (PIKA_ITEM (layer));
switch (result)
{
case GTK_PRINT_OPERATION_RESULT_APPLY:
case GTK_PRINT_OPERATION_RESULT_IN_PROGRESS:
return PIKA_PDB_SUCCESS;
case GTK_PRINT_OPERATION_RESULT_CANCEL:
return PIKA_PDB_CANCEL;
case GTK_PRINT_OPERATION_RESULT_ERROR:
return PIKA_PDB_EXECUTION_ERROR;
}
return PIKA_PDB_EXECUTION_ERROR;
}
#ifndef EMBED_PAGE_SETUP
static PikaPDBStatusType
page_setup (PikaImage *image)
{
GtkPrintOperation *operation;
PikaValueArray *return_vals;
gchar *name;
pika_ui_init (PLUG_IN_BINARY);
operation = gtk_print_operation_new ();
print_page_setup_load (operation, image);
print_page_setup_dialog (operation);
print_page_setup_save (operation, image);
g_object_unref (operation);
/* now notify a running print procedure about this change */
name = print_temp_proc_name (image);
/* we don't want the core to show an error message if the
* temporary procedure does not exist
*/
pika_plug_in_set_pdb_error_handler (pika_get_plug_in (),
PIKA_PDB_ERROR_HANDLER_PLUGIN);
return_vals = pika_pdb_run_procedure (pika_get_pdb (),
name,
PIKA_TYPE_IMAGE, image,
G_TYPE_NONE);
pika_value_array_unref (return_vals);
g_free (name);
return PIKA_PDB_SUCCESS;
}
#endif
static void
print_show_error (const gchar *message)
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (NULL, 0,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK,
"%s",
_("An error occurred while trying to print:"));
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", message);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
}
static void
print_operation_set_name (GtkPrintOperation *operation,
PikaImage *image)
{
gchar *name = pika_image_get_name (image);
gtk_print_operation_set_job_name (operation, name);
g_free (name);
}
static void
begin_print (GtkPrintOperation *operation,
GtkPrintContext *context,
PrintData *data)
{
gtk_print_operation_set_use_full_page (operation, data->use_full_page);
pika_progress_init (_("Printing"));
}
static void
end_print (GtkPrintOperation *operation,
GtkPrintContext *context,
PikaLayer **layer)
{
/* we don't need the print layer any longer, delete it */
if (pika_item_is_valid (PIKA_ITEM (*layer)))
{
pika_item_delete (PIKA_ITEM (*layer));
*layer = NULL;
}
pika_progress_end ();
/* generate events to solve the problems described in bug #466928 */
g_timeout_add_seconds (1, (GSourceFunc) gtk_true, NULL);
}
static void
draw_page (GtkPrintOperation *operation,
GtkPrintContext *context,
gint page_nr,
PrintData *data)
{
GError *error = NULL;
if (print_draw_page (context, data, &error))
{
pika_progress_update (1.0);
}
else
{
print_show_error (error->message);
g_error_free (error);
}
}
/*
* This callback creates a "custom" widget that gets inserted into the
* print operation dialog.
*/
static GtkWidget *
create_custom_widget (GtkPrintOperation *operation,
PrintData *data)
{
return print_page_layout_gui (data, PRINT_PROC_NAME);
}
#ifndef EMBED_PAGE_SETUP
static PikaValueArray *
print_temp_proc_run (PikaProcedure *procedure,
const PikaValueArray *args,
gpointer run_data)
{
PikaImage *image = PIKA_VALUES_GET_IMAGE (args, 0);
if (print_operation)
print_page_setup_load (print_operation, image);
return pika_procedure_new_return_values (procedure, PIKA_PDB_SUCCESS, NULL);
}
static gchar *
print_temp_proc_name (PikaImage *image)
{
return g_strdup_printf (PRINT_TEMP_PROC_NAME "-%d",
pika_image_get_id (image));
}
static gchar *
print_temp_proc_install (PikaImage *image)
{
PikaPlugIn *plug_in = pika_get_plug_in ();
gchar *name = print_temp_proc_name (image);
PikaProcedure *procedure;
procedure = pika_procedure_new (plug_in, name,
PIKA_PDB_PROC_TYPE_TEMPORARY,
print_temp_proc_run, NULL, NULL);
pika_procedure_set_documentation (procedure,
"DON'T USE THIS ONE",
"Temporary procedure to notify the "
"Print plug-in about changes to the "
"Page Setup.",
NULL);
pika_procedure_set_attribution (procedure,
"Sven Neumann",
"Sven Neumann",
"2008");
PIKA_PROC_ARG_IMAGE (procedure, "image",
"Image",
"The image to notify about",
FALSE,
G_PARAM_READWRITE);
pika_plug_in_add_temp_procedure (plug_in, procedure);
g_object_unref (procedure);
return name;
}
#endif

60
plug-ins/print/print.h Normal file
View File

@ -0,0 +1,60 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 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 <https://www.gnu.org/licenses/>.
*/
#ifndef G_OS_WIN32
#define EMBED_PAGE_SETUP 1
#endif
#define PIKA_PLUGIN_PRINT_ERROR pika_plugin_print_error_quark ()
typedef enum
{
PIKA_PLUGIN_PRINT_ERROR_FAILED
} PikaPluginPrintError;
GQuark pika_plugin_print_error_quark (void);
typedef enum
{
CENTER_NONE = 0,
CENTER_HORIZONTALLY = 1,
CENTER_VERTICALLY = 2,
CENTER_BOTH = 3
} PrintCenterMode;
typedef struct
{
PikaImage *image;
PikaDrawable *drawable;
PikaUnit unit;
gdouble xres;
gdouble yres;
gdouble min_xres;
gdouble min_yres;
PikaUnit image_unit;
gdouble offset_x;
gdouble offset_y;
PrintCenterMode center;
gboolean use_full_page;
gboolean draw_crop_marks;
GtkPrintOperation *operation;
} PrintData;