/* Eye Of GNOME -- Print Dialog Custom Widget
 *
 * Copyright (C) 2006-2007 The Free Software Foundation
 *
 * Author: Claudio Saavedra <csaavedra@alumnos.utalca.cl>
 *
 * 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.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gtk/gtk.h>

#include <glib/gi18n.h>
#include <glib/gprintf.h>

#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
#include <langinfo.h>
#endif

#include "eog-print-image-setup.h"
#include "eog-print-preview.h"

/**
 * SECTION:
 * @Title: Printing Custom Widget
 * @Short_Description: a custom widget to setup image prints.
 * @Stability_Level: Internal
 * @See_Also: #EogPrintPreview
 *
 * This widget is to be used as the custom widget in a #GtkPrintUnixDialog in
 * EOG. Through it, you can set the position and scaling of a image
 * interactively.
 */

struct _EogPrintImageSetupPrivate {
	GtkWidget *left;
	GtkWidget *right;
	GtkWidget *top;
	GtkWidget *bottom;

	GtkWidget *center;

	GtkWidget *width;
	GtkWidget *height;

	GtkWidget *scaling;
	GtkWidget *unit;

	GtkUnit current_unit;

	EogImage *image;
	GtkPageSetup *page_setup;

	GtkWidget *preview;
};

enum {
	PROP_0,
	PROP_IMAGE,
	PROP_PAGE_SETUP
};

enum {
	CENTER_NONE,
	CENTER_HORIZONTAL,
	CENTER_VERTICAL,
	CENTER_BOTH
};

enum {
	CHANGE_HORIZ,
	CHANGE_VERT
};

enum {
	UNIT_INCH,
	UNIT_MM
};

#define FACTOR_INCH_TO_MM 25.4
#define FACTOR_INCH_TO_PIXEL 72.
#define FACTOR_MM_TO_INCH 0.03937007874015748
#define FACTOR_MM_TO_PIXEL 2.834645669

static void eog_print_image_setup_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void eog_print_image_setup_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);

static void on_left_value_changed   (GtkSpinButton *spinbutton, gpointer user_data);
static void on_right_value_changed  (GtkSpinButton *spinbutton, gpointer user_data);
static void on_top_value_changed    (GtkSpinButton *spinbutton, gpointer user_data);
static void on_bottom_value_changed (GtkSpinButton *spinbutton, gpointer user_data);
static void on_width_value_changed  (GtkSpinButton *spinbutton, gpointer user_data);
static void on_height_value_changed (GtkSpinButton *spinbutton, gpointer user_data);
static gboolean on_scale_changed    (GtkRange      *range     , gpointer user_data);

static void adjust_left_value   (EogPrintImageSetup *setup, gdouble new_value);
static void adjust_right_value  (EogPrintImageSetup *setup, gdouble new_value);
static void adjust_top_value    (EogPrintImageSetup *setup, gdouble new_value);
static void adjust_bottom_value (EogPrintImageSetup *setup, gdouble new_value);
static void adjust_width_value  (EogPrintImageSetup *setup, gdouble new_value);
static void adjust_height_value (EogPrintImageSetup *setup, gdouble new_value);
static void adjust_scale_value  (EogPrintImageSetup *setup, gdouble new_value);
static void adjust_left_range   (EogPrintImageSetup *setup, gdouble new_value);
static void adjust_right_range  (EogPrintImageSetup *setup, gdouble new_value);
static void adjust_top_range    (EogPrintImageSetup *setup, gdouble new_value);
static void adjust_bottom_range (EogPrintImageSetup *setup, gdouble new_value);

G_DEFINE_TYPE_WITH_PRIVATE (EogPrintImageSetup, eog_print_image_setup, GTK_TYPE_GRID);

static gdouble
get_scale_to_px_factor (EogPrintImageSetup *setup)
{
	gdouble factor = 0.;

	switch (setup->priv->current_unit) {
	case GTK_UNIT_MM:
		factor = FACTOR_MM_TO_PIXEL;
		break;
	case GTK_UNIT_INCH:
		factor = FACTOR_INCH_TO_PIXEL;
		break;
	default:
		g_assert_not_reached ();
	}

	return factor;
}

static gdouble
get_max_percentage (EogPrintImageSetup *setup)
{
	EogPrintImageSetupPrivate *priv = setup->priv;
	gdouble p_width, p_height;
	gdouble width, height;
	gint pix_width, pix_height;
	gdouble perc;

	p_width = gtk_page_setup_get_page_width (priv->page_setup, GTK_UNIT_INCH);
	p_height = gtk_page_setup_get_page_height (priv->page_setup, GTK_UNIT_INCH);

	eog_image_get_size (priv->image, &pix_width, &pix_height);

	width  = (gdouble)pix_width/FACTOR_INCH_TO_PIXEL;
	height = (gdouble)pix_height/FACTOR_INCH_TO_PIXEL;

	if (p_width > width && p_height > height) {
		perc = 1.;
	} else {
		perc = MIN (p_width/width, p_height/height);
	}

	return perc;
}

static void
center_horizontal (EogPrintImageSetup *setup,
	gdouble       factor,
	gdouble       width,
	gdouble       height)
{
	EogPrintImageSetupPrivate *priv;
	priv = setup->priv;
	gdouble page_width = gtk_page_setup_get_page_width (priv->page_setup,priv->current_unit);
	gdouble scale = 0.01*gtk_range_get_value (GTK_RANGE (priv->scaling));
	gdouble left_is_right = (page_width - width*scale)/2;
	adjust_left_value (setup,left_is_right);
	adjust_right_value(setup,left_is_right);
}

static void
center_vertical (EogPrintImageSetup *setup,
	gdouble       factor,
	gdouble       width,
	gdouble       height)
{
	EogPrintImageSetupPrivate *priv;
	priv = setup->priv;
	gdouble page_height = gtk_page_setup_get_page_height (priv->page_setup, priv->current_unit);
	gdouble scale = 0.01*gtk_range_get_value (GTK_RANGE (priv->scaling));
	gdouble top_is_bottom   = (page_height - height*scale)/2;
	adjust_top_value   (setup,top_is_bottom);
	adjust_bottom_value(setup,top_is_bottom);
}

static void
on_center_changed (GtkComboBox *combobox,
		   gpointer user_data)
{
	EogPrintImageSetup *setup;
	EogPrintImageSetupPrivate *priv;
	gint active;
	gint pix_width, pix_height;
	gdouble pos_x, pos_y;
	gdouble factor, width, height;


	setup = EOG_PRINT_IMAGE_SETUP (user_data);
	priv = setup->priv;

	active = gtk_combo_box_get_active (combobox);

	eog_image_get_size (priv->image, &pix_width, &pix_height);
	factor = get_scale_to_px_factor (setup);
	width = (gdouble)pix_width/factor;
	height = (gdouble)pix_height/factor;

	switch (active) {
	case CENTER_HORIZONTAL:
		center_horizontal (setup, factor, width, height);
		break;
	case CENTER_VERTICAL:
		center_vertical (setup, factor, width, height);
		break;
	case CENTER_BOTH:
		center_horizontal (setup, factor, width, height);
		center_vertical   (setup, factor, width, height);
		break;
	case CENTER_NONE:
	default:
			return;
		break;
	}

	pos_x = gtk_spin_button_get_value (GTK_SPIN_BUTTON (setup->priv->left));
	pos_y = gtk_spin_button_get_value (GTK_SPIN_BUTTON (setup->priv->top));
	if (setup->priv->current_unit == GTK_UNIT_MM) {
		pos_x *= FACTOR_MM_TO_INCH;
		pos_y *= FACTOR_MM_TO_INCH;
	}
	eog_print_preview_set_image_position (EOG_PRINT_PREVIEW (setup->priv->preview), pos_x, pos_y);
}

static void
adjust_center_value (gpointer user_data, gint new_value)
{
	EogPrintImageSetup *setup;
	setup = EOG_PRINT_IMAGE_SETUP (user_data);
	EogPrintImageSetupPrivate *priv = setup->priv;
	g_signal_handlers_block_by_func (priv->center, on_center_changed, setup);
	gtk_combo_box_set_active (GTK_COMBO_BOX (priv->center), new_value);
	g_signal_handlers_unblock_by_func (priv->center, on_center_changed, setup);
}

static gboolean
on_scale_changed (GtkRange     *range,
		  gpointer      user_data)
{
	gdouble scale;
	gdouble width, height;
	gdouble width_delta, height_delta;
	gint pix_width, pix_height;
	gint center_state;
	gdouble left, right, top, bottom;
	gdouble page_width, page_height;
	EogPrintImageSetupPrivate *priv;
	EogPrintImageSetup *setup;
	gdouble factor;

	setup = EOG_PRINT_IMAGE_SETUP (user_data);
	priv = setup->priv;

	center_state = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->center));

	eog_image_get_size (priv->image, &pix_width, &pix_height);

	factor = get_scale_to_px_factor (setup);

	width = (gdouble)pix_width/factor;
	height = (gdouble)pix_height/factor;

	left   = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->left));
	right  = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->right));
	top    = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->top));
	bottom = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->bottom));

	scale = CLAMP (0.01*gtk_range_get_value (range), 0, get_max_percentage (setup));

	adjust_scale_value(user_data, 100*scale);

	eog_print_preview_set_scale (EOG_PRINT_PREVIEW (priv->preview), scale);

	width  *= scale;
	height *= scale;

	page_width = gtk_page_setup_get_page_width (priv->page_setup, priv->current_unit);
	page_height = gtk_page_setup_get_page_height (priv->page_setup, priv->current_unit);

	width_delta  = page_width - left - right -  width;
	height_delta = page_height - top - bottom - height;

	switch (center_state)
	{
		case CENTER_HORIZONTAL:
			left   += width_delta/2;
			right  += width_delta/2;
			bottom += height_delta;
			break;
		case CENTER_VERTICAL:
			right  += width_delta;
			top    += height_delta/2;
			bottom += height_delta/2;
			break;
		case CENTER_BOTH:
			left   += width_delta/2;
			right  += width_delta/2;
			top    += height_delta/2;
			bottom += height_delta/2;
			break;
		default:
			right  += width_delta;
			bottom += height_delta;
			break;
	};
	if (left < 0) {
		right += -left;
		left   = 0;
	};
	if (right < 0) {
		left += -right;
		right = 0;
	};
	if (top < 0) {
		bottom += -top;
		top     = 0;
	};
	if (bottom < 0) {
		top += -bottom;
		bottom = 0;
	};
	adjust_width_value (user_data, width);
	adjust_height_value(user_data, height);
	adjust_left_value  (user_data, left);
	adjust_right_value (user_data, right);
	adjust_top_value   (user_data, top);
	adjust_bottom_value(user_data, bottom);
	gdouble max_left_or_right = page_width  - width;
	gdouble max_top_or_bottom = page_height - height;
	adjust_left_range  (user_data, max_left_or_right);
	adjust_right_range (user_data, max_left_or_right);
	adjust_top_range   (user_data, max_top_or_bottom);
	adjust_bottom_range(user_data, max_top_or_bottom);

	if (setup->priv->current_unit == GTK_UNIT_MM) {
		left *= FACTOR_MM_TO_INCH;
		top  *= FACTOR_MM_TO_INCH;
	}
	eog_print_preview_set_image_position (EOG_PRINT_PREVIEW (setup->priv->preview), left, top);
	return FALSE;
}

static void
adjust_scale_value (EogPrintImageSetup *setup, gdouble new_value)
{
	EogPrintImageSetupPrivate *priv = setup->priv;
	g_signal_handlers_block_by_func (priv->scaling, on_scale_changed, setup);
	gtk_range_set_value (GTK_RANGE (priv->scaling), new_value);
	g_signal_handlers_unblock_by_func (priv->scaling, on_scale_changed, setup);
}

static gchar *
on_scale_format_value (GtkScale *scale,
		       gdouble value)
{
	return g_strdup_printf ("%i%%", (gint)value);
}

static void
on_left_value_changed (GtkSpinButton *spinbutton,
		       gpointer       user_data)
{
	EogPrintImageSetupPrivate *priv;
	EogPrintImageSetup *setup;
	setup = EOG_PRINT_IMAGE_SETUP (user_data);
	priv = setup->priv;
	gint center_state  = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->center));
	gdouble left       = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->left));
	gdouble top        = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->top));
	gdouble scale      = gtk_range_get_value (GTK_RANGE (priv->scaling));
	gdouble page_width = gtk_page_setup_get_page_width (priv->page_setup,
								priv->current_unit);
	gint pix_width, pix_height;
	gdouble factor, width;
	eog_image_get_size (priv->image, &pix_width, &pix_height);
	factor = get_scale_to_px_factor (setup);
	width = (gdouble)pix_width/factor;
	gdouble right = page_width - 0.01*scale*width - left;
	adjust_right_value(user_data,right);
	switch (center_state)
	{
		case CENTER_HORIZONTAL:
			adjust_center_value(user_data,CENTER_NONE);
			break;
		case CENTER_BOTH:
			adjust_center_value(user_data,CENTER_VERTICAL);
			break;
		default:
			break;
	};
	if (setup->priv->current_unit == GTK_UNIT_MM) {
		left *= FACTOR_MM_TO_INCH;
		top  *= FACTOR_MM_TO_INCH;
	}
	eog_print_preview_set_image_position (EOG_PRINT_PREVIEW (setup->priv->preview), left, top);
}

static void
adjust_left_value (EogPrintImageSetup *setup, gdouble new_value)
{
	EogPrintImageSetupPrivate *priv = setup->priv;
	g_signal_handlers_block_by_func (priv->left, on_left_value_changed, setup);
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->left), new_value);
	g_signal_handlers_unblock_by_func (priv->left, on_left_value_changed, setup);
}

static void
adjust_left_range (EogPrintImageSetup *setup, gdouble range)
{
	EogPrintImageSetupPrivate *priv = setup->priv;
	g_signal_handlers_block_by_func (priv->left, on_left_value_changed, setup);
	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->left),0, range);
	g_signal_handlers_unblock_by_func (priv->left, on_left_value_changed, setup);
}

static void
on_right_value_changed (GtkSpinButton *spinbutton,
		       gpointer       user_data)
{
	EogPrintImageSetupPrivate *priv;

	EogPrintImageSetup *setup;
	setup = EOG_PRINT_IMAGE_SETUP (user_data);
	priv = setup->priv;
	gint center_state  = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->center));
	gdouble right      = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->right));
	gdouble top        = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->top));
	gdouble scale      = gtk_range_get_value (GTK_RANGE (priv->scaling));
	gdouble page_width = gtk_page_setup_get_page_width (priv->page_setup,
								priv->current_unit);
	gint pix_width, pix_height;
	gdouble factor, width;
	eog_image_get_size (priv->image, &pix_width, &pix_height);
	factor = get_scale_to_px_factor (setup);
	width = (gdouble)pix_width/factor;
	gdouble left      = page_width - 0.01*scale*width - right;
	adjust_left_value(user_data,left);
	switch (center_state)
	{
		case CENTER_HORIZONTAL:
			adjust_center_value(user_data,CENTER_NONE);
			break;
		case CENTER_BOTH:
			adjust_center_value(user_data,CENTER_VERTICAL);
			break;
		default:
			break;
	};
	if (setup->priv->current_unit == GTK_UNIT_MM) {
		left *= FACTOR_MM_TO_INCH;
		top  *= FACTOR_MM_TO_INCH;
	}
	eog_print_preview_set_image_position (EOG_PRINT_PREVIEW (setup->priv->preview), left, top);
}

static void
adjust_right_value (EogPrintImageSetup *setup, gdouble new_value)
{
	EogPrintImageSetupPrivate *priv = setup->priv;
	g_signal_handlers_block_by_func (priv->right, on_right_value_changed, setup);
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->right), new_value);
	g_signal_handlers_unblock_by_func (priv->right, on_right_value_changed, setup);
}

static void
adjust_right_range (EogPrintImageSetup *setup, gdouble range)
{
	EogPrintImageSetupPrivate *priv = setup->priv;
	g_signal_handlers_block_by_func (priv->right, on_right_value_changed, setup);
	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->right),0, range);
	g_signal_handlers_unblock_by_func (priv->right, on_right_value_changed, setup);
}

static void
on_top_value_changed (GtkSpinButton *spinbutton,
		       gpointer       user_data)
{
	EogPrintImageSetupPrivate *priv;

	EogPrintImageSetup *setup;
	setup = EOG_PRINT_IMAGE_SETUP (user_data);
	priv = setup->priv;
	gint center_state   = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->center));
	gdouble left        = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->left));
	gdouble top         = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->top));
	gdouble scale       = gtk_range_get_value (GTK_RANGE (priv->scaling));
	gdouble page_height = gtk_page_setup_get_page_height (priv->page_setup,
								priv->current_unit);
	gint pix_width, pix_height;
	gdouble factor, height;
	eog_image_get_size (priv->image, &pix_width, &pix_height);
	factor = get_scale_to_px_factor (setup);
	height = (gdouble)pix_height/factor;
	gdouble bottom      = page_height - 0.01*scale*height - top;
	adjust_bottom_value(user_data,bottom);
	switch (center_state)
	{
		case CENTER_VERTICAL:
			adjust_center_value(user_data, CENTER_NONE);
			break;
		case CENTER_BOTH:
			adjust_center_value(user_data, CENTER_HORIZONTAL);
			break;
		default:
			break;
	};
	if (setup->priv->current_unit == GTK_UNIT_MM) {
		left *= FACTOR_MM_TO_INCH;
		top  *= FACTOR_MM_TO_INCH;
	}
	eog_print_preview_set_image_position (EOG_PRINT_PREVIEW (setup->priv->preview), left, top);
}

static void
adjust_top_value (EogPrintImageSetup *setup, gdouble new_value)
{
	EogPrintImageSetupPrivate *priv = setup->priv;
	g_signal_handlers_block_by_func (priv->top, on_top_value_changed, setup);
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->top), new_value);
	g_signal_handlers_unblock_by_func (priv->top, on_top_value_changed, setup);
}

static void
adjust_top_range (EogPrintImageSetup *setup, gdouble range)
{
	EogPrintImageSetupPrivate *priv = setup->priv;
	g_signal_handlers_block_by_func (priv->top, on_top_value_changed, setup);
	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->top),0, range);
	g_signal_handlers_unblock_by_func (priv->top, on_top_value_changed, setup);
}

static void
on_bottom_value_changed (GtkSpinButton *spinbutton,
		       gpointer       user_data)
{
	EogPrintImageSetupPrivate *priv;

	EogPrintImageSetup *setup;
	setup = EOG_PRINT_IMAGE_SETUP (user_data);
	priv = setup->priv;
	gint center_state   = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->center));
	gdouble left        = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->left));
	gdouble bottom      = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->bottom));
	gdouble scale       = gtk_range_get_value (GTK_RANGE (priv->scaling));
	gdouble page_height = gtk_page_setup_get_page_height (priv->page_setup,
								priv->current_unit);
	gint pix_width, pix_height;
	gdouble factor, height;
	eog_image_get_size (priv->image, &pix_width, &pix_height);
	factor = get_scale_to_px_factor (setup);
	height = (gdouble)pix_height/factor;
	gdouble top         = page_height - 0.01*scale*height - bottom;
	adjust_top_value(user_data,top);
	switch (center_state)
	{
		case CENTER_VERTICAL:
			adjust_center_value(user_data,CENTER_NONE);
			break;
		case CENTER_BOTH:
			adjust_center_value(user_data,CENTER_HORIZONTAL);
			break;
		default:
			break;
	};
	if (setup->priv->current_unit == GTK_UNIT_MM) {
		left *= FACTOR_MM_TO_INCH;
		top  *= FACTOR_MM_TO_INCH;
	}
	eog_print_preview_set_image_position (EOG_PRINT_PREVIEW (setup->priv->preview), left, top);
}

static void
adjust_bottom_value (EogPrintImageSetup *setup, gdouble new_value)
{
	EogPrintImageSetupPrivate *priv = setup->priv;
	g_signal_handlers_block_by_func (priv->bottom, on_bottom_value_changed, setup);
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->bottom), new_value);
	g_signal_handlers_unblock_by_func (priv->bottom, on_bottom_value_changed, setup);
}

static void
adjust_bottom_range (EogPrintImageSetup *setup, gdouble range)
{
	EogPrintImageSetupPrivate *priv = setup->priv;
	g_signal_handlers_block_by_func (priv->bottom, on_bottom_value_changed, setup);
	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->bottom),0, range);
	g_signal_handlers_unblock_by_func (priv->bottom, on_bottom_value_changed, setup);
}

static void
on_width_value_changed (GtkSpinButton *spinbutton,
			gpointer       user_data)
{
	EogPrintImageSetupPrivate *priv;
	EogPrintImageSetup *setup;
	setup = EOG_PRINT_IMAGE_SETUP (user_data);
	priv = setup->priv;
	gint center_state  = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->center));
	gdouble width      = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->width));
	gdouble left       = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->left));
	gdouble top        = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->top));
	gdouble page_width = gtk_page_setup_get_page_width (priv->page_setup,
								priv->current_unit);
	gdouble scale_previous    = gtk_range_get_value (GTK_RANGE (priv->scaling));
	gdouble factor     = get_scale_to_px_factor (setup);
	gdouble page_height = gtk_page_setup_get_page_height (priv->page_setup,
								priv->current_unit);

	gdouble right,bottom;
	gint pix_width, pix_height;

	eog_image_get_size (priv->image, &pix_width, &pix_height);
	gdouble width_previous  = 0.01*scale_previous * (gdouble)pix_width/factor;

	gdouble scale  = (width/width_previous) * scale_previous;
	gdouble height = 0.01*scale * (gdouble)pix_height/factor;

	adjust_scale_value (user_data,scale);
	adjust_height_value(user_data,height);
	gdouble max_left_or_right = page_width  - width;
	gdouble max_top_or_bottom = page_height - height;
	adjust_left_range  (user_data, max_left_or_right);
	adjust_right_range (user_data, max_left_or_right);
	adjust_top_range   (user_data, max_top_or_bottom);
	adjust_bottom_range(user_data, max_top_or_bottom);

	switch (center_state)
	{
		case CENTER_NONE:
			right  = page_width  - width  - left;
			bottom = page_height - height;
			adjust_right_value (user_data,right);
			adjust_bottom_value(user_data,bottom);
			break;
		case CENTER_HORIZONTAL:
			left   = (page_width  - width)/2;
			right  = left;
			bottom = page_height - height;
			adjust_left_value  (user_data,left);
			adjust_right_value (user_data,right);
			adjust_bottom_value(user_data,bottom);
			break;
		case CENTER_VERTICAL:
			right  = page_width  - width  - left;
			top    = (page_height - height)/2;
			bottom = top;
			adjust_right_value (user_data,right);
			adjust_top_value   (user_data,top);
			adjust_bottom_value(user_data,bottom);
			break;
		default:
			left   = (page_width  - width)/2;
			right  = left;
			top    = (page_height - height)/2;
			bottom = top;
			adjust_left_value  (user_data,left);
			adjust_right_value (user_data,right);
			adjust_top_value   (user_data,top);
			adjust_bottom_value(user_data,bottom);
			break;
	};
	if (setup->priv->current_unit == GTK_UNIT_MM) {
		left *= FACTOR_MM_TO_INCH;
		top  *= FACTOR_MM_TO_INCH;
	}
	eog_print_preview_set_scale (EOG_PRINT_PREVIEW (priv->preview), 0.01*scale);
	eog_print_preview_set_image_position (EOG_PRINT_PREVIEW (setup->priv->preview), left, top);
}

static void
adjust_width_value (EogPrintImageSetup *setup, gdouble new_value)
{
	EogPrintImageSetupPrivate *priv = setup->priv;
	g_signal_handlers_block_by_func (priv->width, on_width_value_changed, setup);
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->width), new_value);
	g_signal_handlers_unblock_by_func (priv->width, on_width_value_changed, setup);
}

static void
on_height_value_changed (GtkSpinButton *spinbutton,
			gpointer       user_data)
{
	EogPrintImageSetupPrivate *priv;
	EogPrintImageSetup *setup;
	setup = EOG_PRINT_IMAGE_SETUP (user_data);
	priv = setup->priv;
	gint center_state  = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->center));
	gdouble height     = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->height));
	gdouble left       = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->left));
	gdouble top        = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->top));
	gdouble page_width = gtk_page_setup_get_page_width (priv->page_setup,
								priv->current_unit);
	gdouble scale_previous    = gtk_range_get_value (GTK_RANGE (priv->scaling));
	gdouble factor     = get_scale_to_px_factor (setup);
	gdouble page_height = gtk_page_setup_get_page_height (priv->page_setup,
								priv->current_unit);

	gdouble right,bottom;
	gint pix_width, pix_height;

	eog_image_get_size (priv->image, &pix_width, &pix_height);
	gdouble height_previous = 0.01*scale_previous * (gdouble)pix_height/factor;

	gdouble scale = (height/height_previous) * scale_previous;
	gdouble width = 0.01*scale * (gdouble)pix_width/factor;

	adjust_scale_value(user_data,scale);
	adjust_width_value(user_data,width);
	gdouble max_left_or_right = page_width  - width;
	gdouble max_top_or_bottom = page_height - height;
	adjust_left_range  (setup, max_left_or_right);
	adjust_right_range (setup, max_left_or_right);
	adjust_top_range   (setup, max_top_or_bottom);
	adjust_bottom_range(setup, max_top_or_bottom);

	switch (center_state)
	{
		case CENTER_NONE:
			right  = page_width  - width  - left;
			bottom = page_height - height;
			adjust_right_value (user_data,right);
			adjust_bottom_value(user_data,bottom);
			break;
		case CENTER_HORIZONTAL:
			left   = (page_width  - width)/2;
			right  = left;
			bottom = page_height - height;
			adjust_left_value  (user_data,left);
			adjust_right_value (user_data,right);
			adjust_bottom_value(user_data,bottom);
			break;
		case CENTER_VERTICAL:
			right  = page_width  - width  - left;
			top    = (page_height - height)/2;
			bottom = top;
			adjust_right_value (user_data,right);
			adjust_top_value   (user_data,top);
			adjust_bottom_value(user_data,bottom);
			break;
		default:
			left   = (page_width  - width)/2;
			right  = left;
			top    = (page_height - height)/2;
			bottom = top;
			adjust_left_value  (user_data,left);
			adjust_right_value (user_data,right);
			adjust_top_value   (user_data,top);
			adjust_bottom_value(user_data,bottom);
			break;
	};
	if (setup->priv->current_unit == GTK_UNIT_MM) {
		left *= FACTOR_MM_TO_INCH;
		top  *= FACTOR_MM_TO_INCH;
	}
	eog_print_preview_set_scale (EOG_PRINT_PREVIEW (priv->preview), 0.01*scale);
	eog_print_preview_set_image_position (EOG_PRINT_PREVIEW (setup->priv->preview), left, top);
}

static void
adjust_height_value (EogPrintImageSetup *setup, gdouble new_value)
{
	EogPrintImageSetupPrivate *priv = setup->priv;
	g_signal_handlers_block_by_func (priv->height, on_height_value_changed, setup);
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->height), new_value);
	g_signal_handlers_unblock_by_func (priv->height, on_height_value_changed, setup);
}

static void
change_unit (GtkSpinButton *spinbutton,
	     gdouble factor,
	     gint digits,
	     gdouble step,
	     gdouble page,
	     gpointer func,
	     gpointer user_data)
{
	gdouble value;
	gdouble range;

	gtk_spin_button_get_range (spinbutton, NULL, &range);
	range *= factor;

	value = gtk_spin_button_get_value (spinbutton);
	value *= factor;

	EogPrintImageSetup *setup;
	setup = EOG_PRINT_IMAGE_SETUP (user_data);
	g_signal_handlers_block_by_func (spinbutton, func, setup);
	gtk_spin_button_set_range (spinbutton, 0, range);
	gtk_spin_button_set_value (spinbutton, value);
	gtk_spin_button_set_digits (spinbutton, digits);
	gtk_spin_button_set_increments  (spinbutton, step, page);
	g_signal_handlers_unblock_by_func (spinbutton, func, setup);
}

static void
set_scale_unit (EogPrintImageSetup *setup,
		GtkUnit unit)
{
	EogPrintImageSetupPrivate *priv = setup->priv;
	gdouble factor;
	gdouble step, page;
	gint digits;

	if (G_UNLIKELY (priv->current_unit == unit))
		return;

	switch (unit) {
	case GTK_UNIT_MM:
		factor = FACTOR_INCH_TO_MM;
		digits = 0;
		step = 1;
		page = 10;
		break;
	case GTK_UNIT_INCH:
		factor = FACTOR_MM_TO_INCH;
		digits = 2;
		step = 0.01;
		page = 0.1;
		break;
	default:
		g_assert_not_reached ();
	}

	change_unit (GTK_SPIN_BUTTON (priv->width), factor, digits, step, page,on_width_value_changed,setup);
	change_unit (GTK_SPIN_BUTTON (priv->height), factor, digits, step, page,on_height_value_changed,setup);
	change_unit (GTK_SPIN_BUTTON (priv->left), factor, digits, step, page,on_left_value_changed,setup);
	change_unit (GTK_SPIN_BUTTON (priv->right), factor, digits, step, page,on_right_value_changed,setup);
	change_unit (GTK_SPIN_BUTTON (priv->top), factor, digits, step, page,on_top_value_changed,setup);
	change_unit (GTK_SPIN_BUTTON (priv->bottom), factor, digits, step, page,on_bottom_value_changed,setup);

	priv->current_unit = unit;
}

static void
on_unit_changed (GtkComboBox *combobox,
		 gpointer user_data)
{
	GtkUnit unit = GTK_UNIT_INCH;

	switch (gtk_combo_box_get_active (combobox)) {
	case UNIT_INCH:
		unit = GTK_UNIT_INCH;
		break;
	case UNIT_MM:
		unit = GTK_UNIT_MM;
		break;
	default:
		g_assert_not_reached ();
	}

	set_scale_unit (EOG_PRINT_IMAGE_SETUP (user_data), unit);
}

static void
on_preview_image_moved (EogPrintPreview *preview,
			gpointer user_data)
{
	EogPrintImageSetupPrivate *priv = EOG_PRINT_IMAGE_SETUP (user_data)->priv;
	gdouble left, right, top, bottom,width, height, page_width, page_height;

	eog_print_preview_get_image_position (preview, &left, &top);

	if (priv->current_unit == GTK_UNIT_MM) {
		left *= FACTOR_INCH_TO_MM;
		top *= FACTOR_INCH_TO_MM;
	}
	width      = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->width));
	height     = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->height));
	page_width = gtk_page_setup_get_page_width (priv->page_setup,
								priv->current_unit);
	page_height = gtk_page_setup_get_page_height (priv->page_setup,
								priv->current_unit);
	right  = page_width  - width  -left;
	bottom = page_height - height -top;
	adjust_left_value  (user_data, left);
	adjust_right_value (user_data, right);
	adjust_top_value   (user_data, top);
	adjust_bottom_value(user_data, bottom);
	adjust_center_value(user_data, CENTER_NONE);
}



static gboolean
on_preview_image_scrolled (GtkWidget *widget,
			   GdkEventScroll *event,
			   gpointer user_data)
{
	EogPrintImageSetupPrivate *priv = EOG_PRINT_IMAGE_SETUP (user_data)->priv;
	EogPrintPreview *preview = EOG_PRINT_PREVIEW (widget);
	gfloat scale;

	scale = eog_print_preview_get_scale (preview);

	if (!eog_print_preview_point_in_image_area (preview,
						    event->x, event->y))
	{
		return FALSE;
	}

	switch (event->direction) {
	case GDK_SCROLL_UP:
		/* scale up */
		scale *= 1.1;
		break;
	case GDK_SCROLL_DOWN:
		/* scale down */
		scale *= 0.9;
		break;
	default:
		return FALSE;
		break;
	}

	// Now trigger SAME function as if scaling widget changed:
	gtk_range_set_value (GTK_RANGE (priv->scaling), 100*scale);
	return TRUE;
}

static gboolean
on_preview_image_key_pressed (GtkWidget *widget,
			      GdkEventKey *event,
			      gpointer user_data)
{
	EogPrintImageSetupPrivate *priv = EOG_PRINT_IMAGE_SETUP (user_data)->priv;
	EogPrintPreview *preview = EOG_PRINT_PREVIEW (widget);
	gfloat scale;

	scale = eog_print_preview_get_scale (preview);

	switch (event->keyval) {
	case GDK_KEY_KP_Add:
	case GDK_KEY_plus:
		/* scale up */
		scale *= 1.1;
		break;
	case GDK_KEY_KP_Subtract:
	case GDK_KEY_minus:
		/* scale down */
		scale *= 0.9;
		break;
	default:
		return FALSE;
		break;
	}

	gtk_range_set_value (GTK_RANGE (priv->scaling), 100*scale);
	return TRUE;
}

/* Function taken from gtkprintunixdialog.c */
static GtkWidget *
wrap_in_frame (const gchar *label,
               GtkWidget   *child)
{
	GtkWidget *frame, *label_widget;
	gchar *bold_text;

	label_widget = gtk_label_new ("");
	gtk_widget_set_halign (label_widget, GTK_ALIGN_START);
	gtk_widget_show (label_widget);

	bold_text = g_markup_printf_escaped ("<b>%s</b>", label);
	gtk_label_set_markup (GTK_LABEL (label_widget), bold_text);
	g_free (bold_text);

	frame = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
	gtk_box_pack_start (GTK_BOX (frame), label_widget, FALSE, FALSE, 0);
	gtk_box_pack_start (GTK_BOX (frame), child, FALSE, FALSE, 0);

	gtk_widget_set_margin_start (child, 12);

	gtk_widget_show (frame);
	return frame;
}

static GtkWidget *
grid_attach_spin_button_with_label (GtkWidget *grid,
				    const gchar* text_label,
				    gint left, gint top)
{
	GtkWidget *label, *spin_button;

	label = gtk_label_new_with_mnemonic (text_label);
	gtk_widget_set_halign (label, GTK_ALIGN_START);
	spin_button = gtk_spin_button_new_with_range (0, 100, 0.01);
	gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spin_button), 2);
	gtk_entry_set_width_chars (GTK_ENTRY (spin_button), 6);
	gtk_grid_attach (GTK_GRID (grid), label, left, top, 1, 1);
	gtk_grid_attach_next_to (GTK_GRID (grid), spin_button, label,
				 GTK_POS_RIGHT, 1, 1);
	gtk_label_set_mnemonic_widget (GTK_LABEL (label), spin_button);

	return spin_button;
}


static void
eog_print_image_setup_set_property (GObject      *object,
				    guint         prop_id,
				    const GValue *value,
				    GParamSpec   *pspec)
{
	EogPrintImageSetup *setup = EOG_PRINT_IMAGE_SETUP (object);
	EogPrintImageSetupPrivate *priv = setup->priv;
	GdkPixbuf *pixbuf;

	switch (prop_id) {
	case PROP_IMAGE:
		if (priv->image) {
			g_object_unref (priv->image);
		}
		priv->image = EOG_IMAGE (g_value_dup_object (value));
		if (EOG_IS_IMAGE (priv->image)) {
			pixbuf = eog_image_get_pixbuf (priv->image);
			g_object_set (priv->preview, "image",
				      pixbuf, NULL);
			g_object_unref (pixbuf);
		}
		break;
	case PROP_PAGE_SETUP:
		priv->page_setup = g_value_get_object (value);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
	}
}

static void
eog_print_image_setup_get_property (GObject    *object,
				    guint       prop_id,
				    GValue     *value,
				    GParamSpec *pspec)
{
	EogPrintImageSetup *setup = EOG_PRINT_IMAGE_SETUP (object);
	EogPrintImageSetupPrivate *priv = setup->priv;

	switch (prop_id) {
	case PROP_IMAGE:
		g_value_set_object (value, priv->image);
		break;
	case PROP_PAGE_SETUP:
		g_value_set_object (value, priv->page_setup);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
	}
}

static void
set_initial_values (EogPrintImageSetup *setup)
{
	EogPrintImageSetupPrivate *priv;
	gint pix_width, pix_height;
	gdouble factor;
	gdouble width, height;
	gdouble max_perc;

	priv = setup->priv;

	factor = get_scale_to_px_factor (setup);

	eog_image_get_size (priv->image, &pix_width, &pix_height);
	width = (gdouble)pix_width/factor;
	height = (gdouble)pix_height/factor;

	max_perc = get_max_percentage (setup);

	width *= max_perc;
	height *= max_perc;

	gtk_range_set_range (GTK_RANGE (priv->scaling), 1, 100*max_perc);
	gtk_range_set_increments (GTK_RANGE (priv->scaling), max_perc, 10*max_perc);
	adjust_scale_value(setup, 100*max_perc);
	eog_print_preview_set_scale (EOG_PRINT_PREVIEW (priv->preview), max_perc);
	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->width), 1, width);
	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->height), 1, height);

	gdouble page_width        = gtk_page_setup_get_page_width (priv->page_setup, priv->current_unit);
	gdouble page_height       = gtk_page_setup_get_page_height (priv->page_setup, priv->current_unit);
	gdouble max_left_or_right = page_width  - width;
	gdouble max_top_or_bottom = page_height - height;

	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->left  ), 0, max_left_or_right);
	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->right ), 0, max_left_or_right);
	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->top   ), 0, max_top_or_bottom);
	gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->bottom), 0, max_top_or_bottom);
	adjust_width_value(setup, width);
	adjust_height_value(setup, height);

	gtk_combo_box_set_active (GTK_COMBO_BOX (priv->center),CENTER_BOTH);

}

static void
connect_signals (EogPrintImageSetup *setup)
{
	EogPrintImageSetupPrivate *priv;

	priv = setup->priv;

	g_signal_connect (G_OBJECT (priv->left), "changed",
			  G_CALLBACK (on_left_value_changed), setup);
	g_signal_connect (G_OBJECT (priv->right), "changed",
			  G_CALLBACK (on_right_value_changed), setup);
	g_signal_connect (G_OBJECT (priv->top), "changed",
			  G_CALLBACK (on_top_value_changed), setup);
	g_signal_connect (G_OBJECT (priv->bottom), "changed",
			  G_CALLBACK (on_bottom_value_changed), setup);
	g_signal_connect (G_OBJECT (priv->width), "changed",
			  G_CALLBACK (on_width_value_changed), setup);
	g_signal_connect (G_OBJECT (priv->height), "changed",
			  G_CALLBACK (on_height_value_changed), setup);
	g_signal_connect (G_OBJECT (priv->scaling), "value-changed",
			  G_CALLBACK (on_scale_changed), setup);
	g_signal_connect (G_OBJECT (priv->scaling), "format-value",
			  G_CALLBACK (on_scale_format_value), NULL);
	g_signal_connect (G_OBJECT (priv->preview), "image-moved",
			  G_CALLBACK (on_preview_image_moved), setup);
	g_signal_connect (G_OBJECT (priv->preview), "scroll-event",
			  G_CALLBACK (on_preview_image_scrolled), setup);
	g_signal_connect (G_OBJECT (priv->preview), "key-press-event",
			  G_CALLBACK (on_preview_image_key_pressed), setup);
}

static void
eog_print_image_setup_class_init (EogPrintImageSetupClass *class)
{
	GObjectClass *object_class = (GObjectClass *)class;

	object_class->set_property = eog_print_image_setup_set_property;
	object_class->get_property = eog_print_image_setup_get_property;

	g_object_class_install_property (object_class, PROP_IMAGE,
					 g_param_spec_object ("image",
							      _("Image"),
							      _("The image whose printing properties will be set up"),
							      EOG_TYPE_IMAGE,
							      G_PARAM_READWRITE));

	g_object_class_install_property (object_class, PROP_PAGE_SETUP,
					 g_param_spec_object ("page-setup",
							      _("Page Setup"),
							      _("The information for the page where the image will be printed"),
							      GTK_TYPE_PAGE_SETUP,
							      G_PARAM_READWRITE));
}

static void
eog_print_image_setup_init (EogPrintImageSetup *setup)
{
	GtkWidget *frame;
	GtkWidget *grid;
	GtkWidget *label;
	GtkWidget *hscale;
	GtkWidget *combobox;
	EogPrintImageSetupPrivate *priv;

#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
	gchar *locale_scale = NULL;
#endif

	priv = setup->priv = eog_print_image_setup_get_instance_private (setup);

	priv->image = NULL;

	grid = gtk_grid_new ();
	gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
	gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
	frame = wrap_in_frame (_("Position"), grid);
	gtk_grid_attach (GTK_GRID (setup), frame, 0, 0, 1, 1);

	priv->left = grid_attach_spin_button_with_label (grid,
							 _("_Left:"), 0, 0);
	priv->right = grid_attach_spin_button_with_label (grid,
							  _("_Right:"), 0, 1);
	priv->top = grid_attach_spin_button_with_label (grid, _("_Top:"), 2, 0);
	priv->bottom = grid_attach_spin_button_with_label (grid, _("_Bottom:"),
							   2, 1);

	label = gtk_label_new_with_mnemonic (_("C_enter:"));
	gtk_widget_set_halign (label, GTK_ALIGN_START);

	combobox = gtk_combo_box_text_new ();
	gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox),
				        CENTER_NONE, _("None"));
	gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox),
				        CENTER_HORIZONTAL, _("Horizontal"));
	gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox),
				        CENTER_VERTICAL, _("Vertical"));
	gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox),
				        CENTER_BOTH, _("Both"));
	gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), CENTER_NONE);
	/* Attach combobox below right margin spinbutton and span until end */
	gtk_grid_attach_next_to (GTK_GRID (grid), combobox, priv->right,
				 GTK_POS_BOTTOM, 3, 1);
	/* Attach the label to the left of the combobox */
	gtk_grid_attach_next_to (GTK_GRID (grid), label, combobox, GTK_POS_LEFT,
				 1, 1);
	gtk_label_set_mnemonic_widget (GTK_LABEL (label), combobox);
	priv->center = combobox;
	g_signal_connect (G_OBJECT (combobox), "changed",
			  G_CALLBACK (on_center_changed), setup);

	grid = gtk_grid_new ();
	gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
	gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
	frame = wrap_in_frame (_("Size"), grid);
	gtk_grid_attach (GTK_GRID (setup), frame, 0, 1, 1, 1);

	priv->width = grid_attach_spin_button_with_label (grid, _("_Width:"),
							   0, 0);
	priv->height = grid_attach_spin_button_with_label (grid, _("_Height:"),
							    2, 0);

	label = gtk_label_new_with_mnemonic (_("_Scaling:"));
	hscale = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 1, 100, 1);
	gtk_scale_set_value_pos (GTK_SCALE (hscale), GTK_POS_RIGHT);
	gtk_range_set_value (GTK_RANGE (hscale), 100);
	gtk_grid_attach_next_to (GTK_GRID (grid), hscale, priv->width,
				 GTK_POS_BOTTOM, 3, 1);
	gtk_grid_attach_next_to (GTK_GRID (grid), label, hscale, GTK_POS_LEFT,
				 1, 1);
	gtk_label_set_mnemonic_widget (GTK_LABEL (label), hscale);
	priv->scaling = hscale;

	label = gtk_label_new_with_mnemonic (_("_Unit:"));
	gtk_widget_set_halign (label, GTK_ALIGN_START);

	combobox = gtk_combo_box_text_new ();
	gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox), UNIT_MM,
					_("Millimeters"));
	gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox),
					UNIT_INCH, _("Inches"));

#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
	locale_scale = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT);
	if (locale_scale && locale_scale[0] == 2) {
		gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), UNIT_INCH);
		set_scale_unit (setup, GTK_UNIT_INCH);
	} else
#endif
	{
		gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), UNIT_MM);
		set_scale_unit (setup, GTK_UNIT_MM);
	}

	gtk_grid_attach_next_to (GTK_GRID (grid), combobox, hscale,
				 GTK_POS_BOTTOM, 3, 1);
	gtk_grid_attach_next_to (GTK_GRID (grid), label, combobox, GTK_POS_LEFT,
				 1, 1);

	gtk_label_set_mnemonic_widget (GTK_LABEL (label), combobox);
	priv->unit = combobox;
	g_signal_connect (G_OBJECT (combobox), "changed",
			  G_CALLBACK (on_unit_changed), setup);

	priv->preview = eog_print_preview_new ();

	/* FIXME: This shouldn't be set by hand */
	gtk_widget_set_size_request (priv->preview, 250, 250);

	frame = wrap_in_frame (_("Preview"), priv->preview);
	/* The preview widget needs to span the whole grid height */
	gtk_grid_attach (GTK_GRID (setup), frame, 1, 0, 1, 2);

	gtk_widget_show_all (GTK_WIDGET (setup));
}


/**
 * eog_print_image_setup_new:
 * @image: the #EogImage to print
 * @page_setup: a #GtkPageSetup specifying the page where
 * the image will be print
 *
 * Creates a new #EogPrintImageSetup widget, to be used as a custom
 * widget in a #GtkPrintUnixDialog. This widgets allows to set
 * the image position and scale in a page.
 *
 * Returns: a new #EogPrintImageSetup
 **/
GtkWidget *
eog_print_image_setup_new (EogImage *image, GtkPageSetup *page_setup)
{
	GtkWidget *setup;
	GtkWidget *preview;

	setup = g_object_new (EOG_TYPE_PRINT_IMAGE_SETUP,
			     "orientation", GTK_ORIENTATION_VERTICAL,
			     "row-spacing", 18,
			     "column-spacing", 18,
			     "border-width", 12,
			     "image", image,
			     "page-setup", page_setup,
			     NULL);

	set_initial_values (EOG_PRINT_IMAGE_SETUP (setup));

	preview = EOG_PRINT_IMAGE_SETUP (setup)->priv->preview;
	eog_print_preview_set_from_page_setup (EOG_PRINT_PREVIEW (preview),
					       page_setup);

	connect_signals (EOG_PRINT_IMAGE_SETUP (setup));

	gdouble left       = gtk_spin_button_get_value (GTK_SPIN_BUTTON (EOG_PRINT_IMAGE_SETUP (setup)->priv->left));
	gdouble top        = gtk_spin_button_get_value (GTK_SPIN_BUTTON (EOG_PRINT_IMAGE_SETUP (setup)->priv->top));
	if (EOG_PRINT_IMAGE_SETUP (setup)->priv->current_unit == GTK_UNIT_MM) {
		left *= FACTOR_MM_TO_INCH;
		top  *= FACTOR_MM_TO_INCH;
	}
	eog_print_preview_set_image_position (EOG_PRINT_PREVIEW (EOG_PRINT_IMAGE_SETUP (setup)->priv->preview), left, top);
	return setup;
}

/**
 * eog_print_image_setup_get_options:
 * @setup: a #EogPrintImageSetup
 * @left: a pointer where to store the image's left position
 * @top: a pointer where to store the image's top position
 * @scale: a pointer where to store the image's scale
 * @unit: a pointer where to store the #GtkUnit used by the @left and @top values.
 *
 * Gets the options set by the #EogPrintImageSetup.
 **/
void
eog_print_image_setup_get_options (EogPrintImageSetup *setup,
				   gdouble *left,
				   gdouble *top,
				   gdouble *scale,
				   GtkUnit *unit)
{
	EogPrintImageSetupPrivate *priv;

	g_return_if_fail (EOG_IS_PRINT_IMAGE_SETUP (setup));

	priv = setup->priv;

	*left = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->left));
	*top = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->top));
	*scale = gtk_range_get_value (GTK_RANGE (priv->scaling));
	*unit = priv->current_unit;
}

void
eog_print_image_setup_update (GtkPrintOperation *operation,
			      GtkWidget         *custom_widget,
			      GtkPageSetup      *page_setup,
			      GtkPrintSettings  *print_settings,
			      gpointer           user_data)
{
	GtkWidget *preview;
	gdouble    pos_x;
	gdouble    pos_y;
	EogPrintImageSetup *setup;

	setup = EOG_PRINT_IMAGE_SETUP (custom_widget);

	setup->priv->page_setup = gtk_page_setup_copy (page_setup);

	set_initial_values (EOG_PRINT_IMAGE_SETUP (setup));

	preview = EOG_PRINT_IMAGE_SETUP (setup)->priv->preview;
	eog_print_preview_set_from_page_setup (EOG_PRINT_PREVIEW (preview),
					       setup->priv->page_setup);

	pos_x = gtk_spin_button_get_value (GTK_SPIN_BUTTON (setup->priv->left));
	pos_y = gtk_spin_button_get_value (GTK_SPIN_BUTTON (setup->priv->top));
	if (setup->priv->current_unit == GTK_UNIT_MM) {
		pos_x *= FACTOR_MM_TO_INCH;
		pos_y *= FACTOR_MM_TO_INCH;
	}
	eog_print_preview_set_image_position (EOG_PRINT_PREVIEW (setup->priv->preview), pos_x, pos_y);
}
