diff options
Diffstat (limited to 'src/gutenprintui2/panel.c')
-rw-r--r-- | src/gutenprintui2/panel.c | 4962 |
1 files changed, 4962 insertions, 0 deletions
diff --git a/src/gutenprintui2/panel.c b/src/gutenprintui2/panel.c new file mode 100644 index 0000000..c8a2ab9 --- /dev/null +++ b/src/gutenprintui2/panel.c @@ -0,0 +1,4962 @@ +/* + * "$Id: panel.c,v 1.4 2005/06/30 01:42:56 rlk Exp $" + * + * Main window code for Print plug-in for the GIMP. + * + * Copyright 1997-2003 Michael Sweet (mike@easysw.com), + * Robert Krawitz (rlk@alum.mit.edu), Steve Miller (smiller@rni.net) + * and Michael Natterer (mitch@gimp.org) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define MAX_PREVIEW_PPI (400) +#define INCH 72 +#define FINCH ((gdouble) INCH) +#define ROUNDUP(x, y) (((x) + ((y) - 1)) / (y)) +#define SCALE(x, y) (((x) + (1.0 / (2.0 * (y)))) * (y)) + +#include <gutenprint/gutenprint-intl-internal.h> +#include <gutenprintui2/gutenprintui.h> +#include "gutenprintui-internal.h" + +#include <string.h> +#include <stdio.h> + +#define MAXIMUM_PARAMETER_LEVEL STP_PARAMETER_LEVEL_ADVANCED4 + +/* + * Constants for GUI. + */ +static int preview_size_vert = 360; +static int preview_size_horiz = 300; +static const int minimum_image_percent = 5.0; +static const int thumbnail_hintw = 128; +static const int thumbnail_hinth = 128; + +#define MOVE_CONSTRAIN 0 +#define MOVE_HORIZONTAL 1 +#define MOVE_VERTICAL 2 +#define MOVE_ANY (MOVE_HORIZONTAL | MOVE_VERTICAL) +#define MOVE_GRID 4 + +/* + * Main window widgets + */ + +static GtkWidget *main_vbox; +static GtkWidget *main_hbox; +static GtkWidget *right_vbox; +static GtkWidget *notebook; + +static GtkWidget *output_color_vbox; +static GtkWidget *cyan_button; +static GtkWidget *magenta_button; +static GtkWidget *yellow_button; +static GtkWidget *black_button; + +static GtkWidget *print_dialog; /* Print dialog window */ + +static GtkWidget *recenter_button; +static GtkWidget *recenter_vertical_button; +static GtkWidget *recenter_horizontal_button; + +static GtkWidget *left_entry; +/* +static GtkWidget *right_entry; +*/ +static GtkWidget *right_border_entry; +static GtkWidget *top_entry; +/* +static GtkWidget *bottom_entry; +*/ +static GtkWidget *bottom_border_entry; +static GtkWidget *width_entry; +static GtkWidget *height_entry; +static GtkWidget *units_hbox; +static GtkWidget *units_label; + +static GtkWidget *custom_size_width; +static GtkWidget *custom_size_height; +static GtkWidget *show_all_paper_sizes_button; +static GtkWidget *auto_paper_size_button; + +static GtkWidget *orientation_menu; /* Orientation menu */ + +static GtkWidget *scaling_percent; /* Scale by percent */ +static GtkWidget *scaling_ppi; /* Scale by pixels-per-inch */ +static GtkWidget *scaling_image; /* Scale to the image */ +static GtkObject *scaling_adjustment; /* Adjustment object for scaling */ + +static GtkWidget *setup_dialog; /* Setup dialog window */ +static GtkWidget *printer_driver; /* Printer driver widget */ +static GtkWidget *printer_model_label; /* Printer model name */ +static GtkWidget *printer_crawler; /* Scrolled Window for menu */ +static GtkWidget *printer_combo; /* Combo for menu */ +static GtkWidget *manufacturer_clist; /* Manufacturer widget */ +static GtkWidget *manufacturer_crawler; /* Scrolled Window for menu */ +static gint plist_callback_id = -1; +static GtkWidget *ppd_file; /* PPD file entry */ +static GtkWidget *ppd_box; +static GtkWidget *ppd_label; /* PPD file entry */ +static GtkWidget *ppd_button; /* PPD file browse button */ +static GtkWidget *ppd_browser; /* File selection dialog for PPDs */ +static GtkWidget *new_printer_dialog; /* New printer dialog window */ +static GtkWidget *new_printer_entry; /* New printer text entry */ +static GtkWidget *file_button; /* PPD file browse button */ +static GtkWidget *file_entry; /* FSD for print files */ +static GtkWidget *file_browser; /* FSD for print files */ +static GtkWidget *standard_cmd_entry; /* FSD for print files */ +static GtkWidget *custom_command_entry; /* FSD for print files */ +static GtkWidget *queue_combo; /* FSD for print files */ +static gint queue_callback_id = -1; + +static GtkWidget *adjust_color_button; +static GtkWidget *about_dialog; + +static GtkWidget *page_size_table; +static GtkWidget *printer_features_table; +static GtkWidget *color_adjustment_table; + +static GtkWidget *copy_count_spin_button; + +static gboolean preview_valid = FALSE; +static gboolean frame_valid = FALSE; +static gboolean need_exposure = FALSE; +static gboolean suppress_scaling_adjustment = FALSE; +static gboolean suppress_scaling_callback = FALSE; +static gboolean thumbnail_update_pending = FALSE; +/* + * These are semaphores, not true booleans. + */ +static gint suppress_preview_update = 0; +static gint suppress_preview_reset = 0; + +static GtkDrawingArea *preview = NULL; /* Preview drawing area widget */ +static GtkDrawingArea *swatch = NULL; +static gint mouse_x, mouse_y; /* Last mouse position */ +static gint orig_top, orig_left; /* Original mouse position at start */ +static gint buttons_pressed = 0; +static gint preview_active = 0; +static gint buttons_mask = 0; +static gint move_constraint = 0; +static gint mouse_button = -1; /* Button being dragged with */ +static gint preview_thumbnail_w, preview_thumbnail_h; +static gint preview_x, preview_y, preview_w, preview_h; + +static gint physical_orientation = -2; /* Actual orientation */ + +static gint paper_width, paper_height; /* Physical width */ +static gint printable_width, printable_height; /* Size of printable area */ +static gint print_width, print_height; /* Printed area of image */ +static gint left, right, top, bottom; /* Imageable region */ +static gint image_width, image_height; /* Image size (possibly rotated) */ +static gint image_true_width, image_true_height; /* Original image */ +static gdouble image_xres, image_yres; /* Original image resolution */ +static gint do_update_thumbnail = 0; +static gint saveme = 0; /* True if printrc should be saved */ +static gint runme = 0; /* True if print should proceed */ +static gint exit_after_file_ok = 0; /* True if we should exit after file browser complete */ +static gint auto_paper_size = 0; /* True if we're using auto paper size now */ + + + +static void scaling_update (GtkAdjustment *adjustment); +static void scaling_callback (GtkWidget *widget); +static void plist_callback (GtkWidget *widget, gpointer data); +static void queue_callback (GtkWidget *widget, gpointer data); +static void custom_media_size_callback(GtkWidget *widget, gpointer data); +static void show_all_paper_sizes_callback(GtkWidget *widget, gpointer data); +static void auto_paper_size_callback(GtkWidget *widget, gpointer data); +static void combo_callback (GtkWidget *widget, gpointer data); +static void output_type_callback (GtkWidget *widget, gpointer data); +static void unit_callback (GtkWidget *widget, gpointer data); +static void orientation_callback (GtkWidget *widget, gpointer data); +static void printandsave_callback (void); +static void about_callback (void); +static void print_callback (void); +static void save_callback (void); +static void setup_callback (GtkWidget *widget); + +static void setup_update (void); +static void setup_open_callback (void); +static void setup_ok_callback (void); +static void setup_cancel_callback (void); +static void new_printer_open_callback (void); +static void new_printer_ok_callback (void); +static void ppd_browse_callback (void); +static void ppd_ok_callback (void); +static void file_browse_callback (void); +static void file_ok_callback (void); +static void file_cancel_callback (void); +static void build_printer_driver_clist(void); +static void print_driver_callback (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *event, + gpointer data); +static void manufacturer_callback (GtkWidget *widget, + gint row, + gint column, + GdkEventButton *event, + gpointer data); +static void command_type_callback (GtkWidget *widget, gpointer data); + +static void do_preview_thumbnail (void); +static void invalidate_preview_thumbnail (void); +static void invalidate_frame (void); + +static GtkWidget *color_adjust_dialog; + +static void preview_update (void); +static void preview_expose (void); +static void preview_button_callback (GtkWidget *widget, + GdkEventButton *bevent, + gpointer data); +static void preview_motion_callback (GtkWidget *widget, + GdkEventMotion *mevent, + gpointer data); +static void position_callback (GtkWidget *widget); +static void position_button_callback (GtkWidget *widget, + gpointer data); +static void copy_count_callback (GtkAdjustment *widget, + gpointer data); +static void plist_build_combo(GtkWidget *combo, + GtkWidget *label, + stp_string_list_t *items, + int active, + const gchar *cur_item, + const gchar *def_value, + GCallback callback, + gint *callback_id, + int (*check_func)(const char *string), + gpointer data); +static void initialize_thumbnail(void); +static void set_color_defaults (void); +static void redraw_color_swatch (void); +static void color_update (GtkAdjustment *adjustment); +static void dimension_update (GtkAdjustment *adjustment); +static void set_controls_active (GtkObject *checkbutton, gpointer optno); +static void update_adjusted_thumbnail (void); + +static void set_media_size(const gchar *new_media_size); +static const stp_printer_t *tmp_printer = NULL; + +static option_t *current_options = NULL; +static int current_option_count = 0; + +static unit_t units[] = + { + { N_("Inch"), N_("Set the base unit of measurement to inches"), + 72.0, NULL, "%.2f" }, + { N_("cm"), N_("Set the base unit of measurement to centimetres"), + 72.0 / 2.54, NULL, "%.2f" }, + { N_("Points"), N_("Set the base unit of measurement to points (1/72\")"), + 1.0, NULL, "%.0f" }, + { N_("mm"), N_("Set the base unit of measurement to millimetres"), + 72.0 / 25.4, NULL, "%.1f" }, + { N_("Pica"), N_("Set the base unit of measurement to picas (1/12\")"), + 72.0 / 12.0, NULL, "%.1f" }, + }; +static const gint unit_count = sizeof(units) / sizeof(unit_t); + +static radio_group_t output_types[] = + { + { N_("Color"), N_("Color output"), "Color", NULL }, + { N_("Grayscale"), + N_("Print in shades of gray using black ink"), "BW", NULL } + }; + +static const gint output_type_count = (sizeof(output_types) / + sizeof(radio_group_t)); + +/* + * The order of these entries must match the order in command_t in + * gutenprintui.h + */ +static radio_group_t command_options[] = + { + { N_("Standard Command"), N_("Use standard print command"), "Standard", NULL }, + { N_("Custom Command"), N_("Use custom print command"), "Custom", NULL }, + { N_("File"), N_("Print to a file"), "File", NULL } + }; + +static const gint command_options_count = (sizeof(command_options) / + sizeof(radio_group_t)); + +static gdouble preview_ppi = 10; + +static stp_string_list_t *printer_list = 0; +static stpui_plist_t *pv; +static const char *manufacturer = 0; + +static gint thumbnail_w, thumbnail_h, thumbnail_bpp; +static guchar *thumbnail_data; +static guchar *adjusted_thumbnail_data; +static guchar *preview_thumbnail_data; + +static void +set_stpui_curve_values(GtkWidget *gcurve, const stp_curve_t *seed) +{ + if (stp_curve_get_gamma(seed)) + { + stpui_curve_set_gamma(STPUI_CURVE(gcurve), stp_curve_get_gamma(seed)); + } + else + { + stp_curve_t *copy = stp_curve_create_copy(seed); + const float *fdata; + size_t count; + stp_curve_resample(copy, 256); + fdata = stp_curve_get_float_data(copy, &count); + stpui_curve_set_vector(STPUI_CURVE(gcurve), count, fdata); + stp_curve_destroy(copy); + } +} + +static void +set_stp_curve_values(GtkWidget *widget, option_t *opt) +{ + int i; + double lo, hi; + gfloat vector[256]; + GtkWidget *gcurve = GTK_WIDGET(widget); + stp_curve_t *curve = stp_curve_create_copy(opt->info.curve.deflt); + stpui_curve_get_vector(STPUI_CURVE(gcurve), 256, vector); + stp_curve_get_bounds(opt->info.curve.deflt, &lo, &hi); + for (i = 0; i < 256; i++) + { + if (vector[i] > hi) + vector[i] = hi; + else if (vector[i] < lo) + vector[i] = lo; + } + switch (STPUI_CURVE(gcurve)->curve_type) + { + case STPUI_CURVE_TYPE_SPLINE: + stp_curve_set_interpolation_type(curve, STP_CURVE_TYPE_SPLINE); + break; + default: + stp_curve_set_interpolation_type(curve, STP_CURVE_TYPE_LINEAR); + break; + } + stp_curve_set_float_data(curve, 256, vector); + stp_set_curve_parameter(pv->v, opt->fast_desc->name, curve); + stp_curve_destroy(curve); +} + +static int +open_curve_editor(GtkObject *button, gpointer xopt) +{ + option_t *opt = (option_t *)xopt; + if (opt->info.curve.is_visible == FALSE) + { + GtkWidget *gcurve = + GTK_WIDGET(STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve); + const stp_curve_t *seed = + stp_get_curve_parameter(pv->v, opt->fast_desc->name); + stp_curve_t *nseed = NULL; + if (!seed) + seed = opt->info.curve.deflt; + if (seed) + nseed = stp_curve_create_copy(seed); + gtk_widget_set_sensitive(GTK_WIDGET(opt->checkbox), FALSE); + gtk_widget_show(GTK_WIDGET(opt->info.curve.dialog)); + set_stpui_curve_values(gcurve, seed); + opt->info.curve.is_visible = TRUE; + if (opt->info.curve.current) + stp_curve_destroy(opt->info.curve.current); + opt->info.curve.current = nseed; + invalidate_preview_thumbnail(); + update_adjusted_thumbnail(); + } +/* gtk_window_activate_focus(GTK_WINDOW(opt->info.curve.dialog)); */ + return 1; +} + +static int +set_default_curve_callback(GtkObject *button, gpointer xopt) +{ + option_t *opt = (option_t *)xopt; + GtkWidget *gcurve = + GTK_WIDGET(STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve); + const stp_curve_t *seed = opt->info.curve.deflt; + set_stpui_curve_values(gcurve, seed); + set_stp_curve_values(gcurve, opt); + invalidate_preview_thumbnail(); + update_adjusted_thumbnail(); + return 1; +} + +static int +set_previous_curve_callback(GtkObject *button, gpointer xopt) +{ + option_t *opt = (option_t *)xopt; + GtkWidget *gcurve = + GTK_WIDGET(STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve); + const stp_curve_t *seed = opt->info.curve.current; + if (!seed) + seed = opt->info.curve.deflt; + set_stpui_curve_values(gcurve, seed); + set_stp_curve_values(gcurve, opt); + invalidate_preview_thumbnail(); + update_adjusted_thumbnail(); + return 1; +} + +static int +set_curve_callback(GtkObject *button, gpointer xopt) +{ + option_t *opt = (option_t *)xopt; + GtkWidget *gcurve = + GTK_WIDGET(STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve); + gtk_widget_hide(opt->info.curve.dialog); + gtk_widget_set_sensitive(GTK_WIDGET(opt->checkbox), TRUE); + opt->info.curve.is_visible = FALSE; + set_stp_curve_values(gcurve, opt); + if (opt->info.curve.current) + stp_curve_destroy(opt->info.curve.current); + opt->info.curve.current = NULL; + invalidate_preview_thumbnail(); + update_adjusted_thumbnail(); + return 1; +} + +static gint +curve_draw_callback(GtkWidget *widget, GdkEvent *event, gpointer xopt) +{ + option_t *opt = (option_t *)xopt; + switch (event->type) + { + case GDK_BUTTON_RELEASE: + set_stp_curve_values(widget, opt); + invalidate_preview_thumbnail(); + update_adjusted_thumbnail(); + break; + default: + break; + } + return 1; +} + +static gint +curve_type_changed(GtkWidget *widget, gpointer xopt) +{ + option_t *opt = (option_t *)xopt; + set_stp_curve_values(widget, opt); + invalidate_preview_thumbnail(); + update_adjusted_thumbnail(); + return 1; +} + +static int +cancel_curve_callback(GtkObject *button, gpointer xopt) +{ + option_t *opt = (option_t *)xopt; + if (opt->info.curve.is_visible) + { + stp_set_curve_parameter(pv->v, opt->fast_desc->name, + opt->info.curve.current); + stp_curve_destroy(opt->info.curve.current); + opt->info.curve.current = NULL; + gtk_widget_hide(opt->info.curve.dialog); + gtk_widget_set_sensitive(GTK_WIDGET(opt->checkbox), TRUE); + opt->info.curve.is_visible = FALSE; + invalidate_preview_thumbnail(); + update_adjusted_thumbnail(); + } + return 1; +} + +static void +stpui_create_curve(option_t *opt, + GtkTable *table, + gint column, + gint row, + const gchar *text, + const stp_curve_t *deflt, + gboolean is_optional) +{ + double lower, upper; + opt->checkbox = gtk_check_button_new(); + gtk_table_attach(GTK_TABLE(table), opt->checkbox, + column, column + 1, row, row + 1, + GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0); + if (is_optional) + gtk_widget_show(opt->checkbox); + else + gtk_widget_hide(opt->checkbox); + + opt->info.curve.label = gtk_label_new(text); + gtk_misc_set_alignment (GTK_MISC (opt->info.curve.label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (table), opt->info.curve.label, + column + 1, column + 2, row, row + 1, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (opt->info.curve.label); + + opt->info.curve.button = gtk_button_new_with_label(_("Edit Curve...")); + g_signal_connect(G_OBJECT(opt->info.curve.button), "clicked", + G_CALLBACK(open_curve_editor), opt); + gtk_table_attach (GTK_TABLE (table), opt->info.curve.button, + column + 2, column + 3, row, row + 1, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(opt->info.curve.button); + + opt->info.curve.dialog = + stpui_dialog_new(_(opt->fast_desc->text), + GTK_WIN_POS_MOUSE, TRUE, + _("Set Default"), set_default_curve_callback, + opt, NULL, NULL, FALSE, FALSE, + _("Restore Previous"), set_previous_curve_callback, + opt, NULL, NULL, FALSE, FALSE, + _("OK"), set_curve_callback, + opt, NULL, NULL, FALSE, FALSE, + _("Cancel"), cancel_curve_callback, + opt, NULL, NULL, FALSE, FALSE, + NULL); + opt->info.curve.gamma_curve = stpui_gamma_curve_new(); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(opt->info.curve.dialog)->vbox), + opt->info.curve.gamma_curve, TRUE, TRUE, 0); + stp_curve_get_bounds(opt->info.curve.deflt, &lower, &upper); + stpui_curve_set_range + (STPUI_CURVE (STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve), + 0.0, 1.0, lower, upper); + gtk_widget_set_usize + (GTK_WIDGET(STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve), 256, 256); + gtk_widget_show(opt->info.curve.gamma_curve); + + g_signal_connect + (G_OBJECT(STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve), + "curve-type-changed", G_CALLBACK(curve_type_changed), opt); + g_signal_connect + (G_OBJECT(STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve), + "event", G_CALLBACK(curve_draw_callback), opt); + + if (opt->fast_desc->help) + { + stpui_set_help_data (opt->info.curve.label, opt->fast_desc->help); + stpui_set_help_data (opt->info.curve.button, opt->fast_desc->help); + stpui_set_help_data (opt->info.curve.gamma_curve, opt->fast_desc->help); + } +} + +static int +checkbox_callback(GtkObject *button, gpointer xopt) +{ + option_t *opt = (option_t *)xopt; + GtkWidget *checkbox = GTK_WIDGET(opt->info.bool.checkbox); + opt->info.bool.current = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox)); + stp_set_boolean_parameter(pv->v, opt->fast_desc->name, + opt->info.bool.current); + invalidate_frame(); + invalidate_preview_thumbnail(); + if (opt->fast_desc->p_class == STP_PARAMETER_CLASS_OUTPUT) + update_adjusted_thumbnail(); + preview_update(); + return 1; +} + +static int +print_mode_is_color(const stp_vars_t *v) +{ + const char *printing_mode = stp_get_string_parameter(v, "PrintingMode"); + if (!printing_mode) + { + int answer = 1; + stp_parameter_t desc; + stp_describe_parameter(v, "PrintingMode", &desc); + if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST && + strcmp(desc.deflt.str, "BW") == 0) + answer = 0; + stp_parameter_description_destroy(&desc); + return answer; + } + if (strcmp(printing_mode, "BW") == 0) + return 0; + else + return 1; +} + +static void +set_current_printer(void) +{ + pv = &(stpui_plist[stpui_plist_current]); + if (print_mode_is_color(pv->v)) + stp_set_string_parameter(pv->v, "PrintingMode", "Color"); + else + stp_set_string_parameter(pv->v, "PrintingMode", "BW"); +} + + +static void +stpui_create_boolean(option_t *opt, + GtkTable *table, + gint column, + gint row, + const gchar *text, + int deflt, + gboolean is_optional) +{ + opt->checkbox = gtk_check_button_new(); + gtk_table_attach(GTK_TABLE(table), opt->checkbox, + column, column + 1, row, row + 1, + GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0); + if (is_optional) + gtk_widget_show(opt->checkbox); + else + gtk_widget_hide(opt->checkbox); + + opt->info.bool.checkbox = + gtk_toggle_button_new_with_label(_(opt->fast_desc->text)); + gtk_table_attach(GTK_TABLE(table), opt->info.bool.checkbox, + column + 1, column + 3, row, row + 1, + GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(opt->info.bool.checkbox); + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(opt->info.bool.checkbox), + stp_get_boolean_parameter(pv->v, opt->fast_desc->name)); + g_signal_connect(G_OBJECT(opt->info.bool.checkbox), "toggled", + G_CALLBACK(checkbox_callback), opt); +} + +static void +build_queue_combo(void) +{ + plist_build_combo(queue_combo, + NULL, + stpui_system_print_queues, + 1, + stpui_plist_get_queue_name(pv), + NULL, + G_CALLBACK(queue_callback), + &queue_callback_id, + NULL, + NULL); +} + +static void +build_printer_combo(void) +{ + int i; + if (printer_list) + stp_string_list_destroy(printer_list); + printer_list = stp_string_list_create(); + for (i = 0; i < stpui_plist_count; i++) + stp_string_list_add_string(printer_list, + stpui_plist[i].name, stpui_plist[i].name); + plist_build_combo(printer_combo, + NULL, + printer_list, + 1, + stp_string_list_param(printer_list, stpui_plist_current)->name, + NULL, + G_CALLBACK(plist_callback), + &plist_callback_id, + NULL, + NULL); +} + +static int +check_page_size(const char *paper_size) +{ + const stp_papersize_t *ps = stp_get_papersize_by_name(paper_size); + if (ps && (ps->paper_unit == PAPERSIZE_ENGLISH_STANDARD || + ps->paper_unit == PAPERSIZE_METRIC_STANDARD)) + return 1; + else + return 0; +} + +static void +build_page_size_combo(option_t *option) +{ + /* + * Some printers don't support any "standard" page sizes. If the number + * of page sizes is small, just display all of them. + */ + if (stpui_show_all_paper_sizes || + stp_string_list_count(option->info.list.params) < 10) + plist_build_combo(option->info.list.combo, option->info.list.label, + option->info.list.params, option->is_active, + stp_get_string_parameter(pv->v, option->fast_desc->name), + option->info.list.default_val,G_CALLBACK(combo_callback), + &(option->info.list.callback_id), NULL, option); + else + plist_build_combo(option->info.list.combo, option->info.list.label, + option->info.list.params, option->is_active, + stp_get_string_parameter(pv->v, option->fast_desc->name), + option->info.list.default_val,G_CALLBACK(combo_callback), + &(option->info.list.callback_id), + check_page_size, option); +} + +static void +build_a_combo(option_t *option) +{ + const gchar *new_value; + stp_parameter_activity_t active; + if (option->fast_desc && + option->fast_desc->p_type == STP_PARAMETER_TYPE_STRING_LIST) + { + const gchar *val = stp_get_string_parameter(pv->v, + option->fast_desc->name); + if (option->info.list.params == NULL || ! option->is_active || + stp_string_list_count(option->info.list.params) == 0) + stp_set_string_parameter(pv->v, option->fast_desc->name, NULL); + else if (!val || strlen(val) == 0 || + ! stp_string_list_is_present(option->info.list.params, val)) + stp_set_string_parameter(pv->v, option->fast_desc->name, + option->info.list.default_val); + if (strcmp(option->fast_desc->name, "PageSize") == 0) + build_page_size_combo(option); + else + plist_build_combo(option->info.list.combo, option->info.list.label, + option->info.list.params, + option->is_active, + stp_get_string_parameter(pv->v, + option->fast_desc->name), + option->info.list.default_val, G_CALLBACK(combo_callback), + &(option->info.list.callback_id), NULL, option); + if (strcmp(option->fast_desc->name, "PageSize") == 0) + set_media_size + (stp_get_string_parameter(pv->v, option->fast_desc->name)); + } + else + plist_build_combo(option->info.list.combo, option->info.list.label, + NULL, 0, "", "", G_CALLBACK(combo_callback), + &(option->info.list.callback_id), NULL, option); + new_value = + stpui_combo_get_name(option->info.list.combo, option->info.list.params); + active = stp_get_string_parameter_active(pv->v, option->fast_desc->name); + stp_set_string_parameter(pv->v, option->fast_desc->name, new_value); + stp_set_string_parameter_active(pv->v, option->fast_desc->name, active); +} + +static void +populate_options(const stp_vars_t *v) +{ + stp_parameter_list_t params = stp_get_parameter_list(v); + int i; + int idx; + if (current_options) + { + for (i = 0; i < current_option_count; i++) + { + option_t *opt = &(current_options[i]); + switch (opt->fast_desc->p_type) + { + case STP_PARAMETER_TYPE_STRING_LIST: + if (opt->info.list.combo) + { + gtk_widget_destroy(opt->info.list.combo); + gtk_widget_destroy(opt->info.list.label); + if (opt->info.list.params) + stp_string_list_destroy(opt->info.list.params); + g_free(opt->info.list.default_val); + } + break; + case STP_PARAMETER_TYPE_DOUBLE: + case STP_PARAMETER_TYPE_DIMENSION: + if (opt->info.flt.adjustment) + { + gtk_widget_destroy + (GTK_WIDGET + (SCALE_ENTRY_SCALE(opt->info.flt.adjustment))); + gtk_widget_destroy + (GTK_WIDGET + (SCALE_ENTRY_LABEL(opt->info.flt.adjustment))); + gtk_widget_destroy + (GTK_WIDGET + (SCALE_ENTRY_SPINBUTTON(opt->info.flt.adjustment))); + } + break; + case STP_PARAMETER_TYPE_CURVE: + gtk_widget_destroy(GTK_WIDGET(opt->info.curve.label)); + gtk_widget_destroy(GTK_WIDGET(opt->info.curve.button)); + gtk_widget_destroy(GTK_WIDGET(opt->info.curve.dialog)); + if (opt->info.curve.current) + stp_curve_destroy(opt->info.curve.current); + break; + case STP_PARAMETER_TYPE_BOOLEAN: + gtk_widget_destroy(GTK_WIDGET(opt->info.bool.checkbox)); + break; + default: + break; + } + if (opt->checkbox) + gtk_widget_destroy(GTK_WIDGET(opt->checkbox)); + } + g_free(current_options); + } + current_option_count = stp_parameter_list_count(params); + current_options = g_malloc(sizeof(option_t) * current_option_count); + + for (idx = 0, i = 0; i < current_option_count; i++) + { + stp_parameter_t desc; + const stp_parameter_t *param = stp_parameter_list_param(params, i); + if (!param->read_only && + (param->p_class == STP_PARAMETER_CLASS_OUTPUT || + param->p_class == STP_PARAMETER_CLASS_FEATURE || + (param->p_class == STP_PARAMETER_CLASS_CORE && + strcmp(param->name, "PageSize") == 0))) + { + option_t *opt = &(current_options[idx]); + opt->fast_desc = stp_parameter_list_param(params, i); + stp_describe_parameter(v, opt->fast_desc->name, &desc); + opt->checkbox = NULL; + opt->is_active = 0; + opt->is_enabled = 0; + switch (opt->fast_desc->p_type) + { + case STP_PARAMETER_TYPE_STRING_LIST: + opt->info.list.callback_id = -1; + opt->info.list.default_val = g_strdup(desc.deflt.str); + if (desc.bounds.str) + opt->info.list.params = + stp_string_list_create_copy(desc.bounds.str); + else + opt->info.list.params = NULL; + opt->info.list.combo = NULL; + opt->info.list.label = NULL; + opt->is_active = desc.is_active; + break; + case STP_PARAMETER_TYPE_DOUBLE: + opt->info.flt.adjustment = NULL; + opt->info.flt.upper = desc.bounds.dbl.upper; + opt->info.flt.lower = desc.bounds.dbl.lower; + opt->info.flt.deflt = desc.deflt.dbl; + opt->info.flt.scale = 1.0; + opt->is_active = desc.is_active; + break; + case STP_PARAMETER_TYPE_DIMENSION: + opt->info.flt.adjustment = NULL; + opt->info.flt.upper = desc.bounds.dimension.upper; + opt->info.flt.lower = desc.bounds.dimension.lower; + opt->info.flt.deflt = desc.deflt.dimension; + opt->info.flt.scale = 1.0; + opt->is_active = desc.is_active; + break; + case STP_PARAMETER_TYPE_CURVE: + opt->info.curve.label = NULL; + opt->info.curve.button = NULL; + opt->info.curve.dialog = NULL; + opt->info.curve.gamma_curve = NULL; + opt->info.curve.current = NULL; + opt->info.curve.deflt = desc.deflt.curve; + opt->info.curve.is_visible = FALSE; + opt->is_active = desc.is_active; + break; + case STP_PARAMETER_TYPE_BOOLEAN: + opt->info.bool.checkbox = NULL; + opt->info.bool.current = 0; + opt->info.bool.deflt = desc.deflt.boolean; + opt->is_active = desc.is_active; + default: + break; + } + idx++; + stp_parameter_description_destroy(&desc); + } + } + current_option_count = idx; + stp_parameter_list_destroy(params); +} + +static void +populate_option_table(GtkWidget *table, int p_class) +{ + int i, j; + int current_pos = 0; + int counts[STP_PARAMETER_LEVEL_INVALID][STP_PARAMETER_TYPE_INVALID]; + int vpos[STP_PARAMETER_LEVEL_INVALID][STP_PARAMETER_TYPE_INVALID]; + for (i = 0; i < STP_PARAMETER_LEVEL_INVALID; i++) + for (j = 0; j < STP_PARAMETER_TYPE_INVALID; j++) + { + vpos[i][j] = 0; + counts[i][j] = 0; + } + + + /* First scan the options to figure out where to start */ + for (i = 0; i < current_option_count; i++) + { + const stp_parameter_t *desc = current_options[i].fast_desc; + /* + * Specialize the core parameters (page size is the only one we want) + * Yuck. + */ + if (!desc->read_only && desc->p_class == p_class && + (desc->p_class != STP_PARAMETER_CLASS_CORE || + strcmp(desc->name, "PageSize") == 0)) + { + switch (desc->p_type) + { + case STP_PARAMETER_TYPE_STRING_LIST: + case STP_PARAMETER_TYPE_DIMENSION: + case STP_PARAMETER_TYPE_DOUBLE: + case STP_PARAMETER_TYPE_CURVE: + case STP_PARAMETER_TYPE_BOOLEAN: + counts[desc->p_level][desc->p_type]++; + break; + default: + break; + } + } + } + + /* Now, figure out where we're going to put the options */ + for (i = 0; i < STP_PARAMETER_LEVEL_INVALID; i++) + { + int level_count = 0; + for (j = 0; j < STP_PARAMETER_TYPE_INVALID; j++) + level_count += counts[i][j]; + if (level_count > 0 && current_pos > 0) + { + GtkWidget *sep = gtk_hseparator_new(); + gtk_table_attach (GTK_TABLE(table), sep, 0, 4, + current_pos, current_pos + 1, + GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0); + if (i <= MAXIMUM_PARAMETER_LEVEL) + gtk_widget_show(sep); + current_pos++; + } + for (j = 0; j < STP_PARAMETER_TYPE_INVALID; j++) + { + vpos[i][j] = current_pos; + current_pos += counts[i][j]; + } + } + + for (i = 0; i < current_option_count; i++) + { + option_t *opt = &(current_options[i]); + const stp_curve_t *xcurve; + const stp_parameter_t *desc = opt->fast_desc; + if (!desc->read_only && desc->p_class == p_class && + (desc->p_class != STP_PARAMETER_CLASS_CORE || + strcmp(desc->name, "PageSize") == 0)) + { + gdouble unit_scaler; + gdouble minor_increment; + gint digits; + switch (desc->p_type) + { + case STP_PARAMETER_TYPE_STRING_LIST: + stpui_create_new_combo(opt, table, 0, + vpos[desc->p_level][desc->p_type]++, + !(desc->is_mandatory)); + if (desc->p_level > MAXIMUM_PARAMETER_LEVEL) + stp_set_string_parameter_active(pv->v, desc->name, + STP_PARAMETER_INACTIVE); + break; + case STP_PARAMETER_TYPE_DOUBLE: + stpui_create_scale_entry(opt, GTK_TABLE(table), 0, + vpos[desc->p_level][desc->p_type]++, + _(desc->text), 200, 0, + opt->info.flt.deflt, + opt->info.flt.lower, + opt->info.flt.upper, + .001, .01, 3, TRUE, 0, 0, NULL, + !(desc->is_mandatory)); + stpui_set_adjustment_tooltip(opt->info.flt.adjustment, + _(desc->help)); + g_signal_connect(G_OBJECT(opt->info.flt.adjustment), + "value_changed", + G_CALLBACK(color_update), opt); + if (desc->p_level > MAXIMUM_PARAMETER_LEVEL) + stp_set_float_parameter_active(pv->v, desc->name, + STP_PARAMETER_INACTIVE); + break; + case STP_PARAMETER_TYPE_DIMENSION: + unit_scaler = units[pv->unit].scale; + if (unit_scaler > 100) + { + digits = 3; + minor_increment = .001; + } + else if (unit_scaler > 10) + { + digits = 2; + minor_increment = .01; + } + else if (unit_scaler > 1) + { + digits = 1; + minor_increment = .1; + } + else + { + digits = 0; + minor_increment = 1; + } + stpui_create_scale_entry(opt, GTK_TABLE(table), 0, + vpos[desc->p_level][desc->p_type]++, + _(desc->text), 200, 0, + opt->info.flt.deflt / unit_scaler, + opt->info.flt.lower / unit_scaler, + opt->info.flt.upper / unit_scaler, + minor_increment, minor_increment * 10, + digits, TRUE, 0, 0, NULL, + !(desc->is_mandatory)); + stpui_set_adjustment_tooltip(opt->info.flt.adjustment, + _(desc->help)); + g_signal_connect(G_OBJECT(opt->info.flt.adjustment), + "value_changed", + G_CALLBACK(dimension_update), opt); + if (desc->p_level > MAXIMUM_PARAMETER_LEVEL) + stp_set_dimension_parameter_active(pv->v, desc->name, + STP_PARAMETER_INACTIVE); + break; + case STP_PARAMETER_TYPE_CURVE: + xcurve = stp_get_curve_parameter(pv->v, opt->fast_desc->name); + if (xcurve) + opt->info.curve.current = stp_curve_create_copy(xcurve); + else + opt->info.curve.current = NULL; + stpui_create_curve(opt, GTK_TABLE(table), 0, + vpos[desc->p_level][desc->p_type]++, + _(desc->text), opt->info.curve.deflt, + !(desc->is_mandatory)); + if (desc->p_level > MAXIMUM_PARAMETER_LEVEL) + stp_set_curve_parameter_active(pv->v, desc->name, + STP_PARAMETER_INACTIVE); + break; + case STP_PARAMETER_TYPE_BOOLEAN: + opt->info.bool.current = + stp_get_boolean_parameter(pv->v, opt->fast_desc->name); + stpui_create_boolean(opt, GTK_TABLE(table), 0, + vpos[desc->p_level][desc->p_type]++, + _(desc->text), opt->info.bool.deflt, + !(desc->is_mandatory)); + if (desc->p_level > MAXIMUM_PARAMETER_LEVEL) + stp_set_boolean_parameter_active(pv->v, desc->name, + STP_PARAMETER_INACTIVE); + break; + case STP_PARAMETER_TYPE_INT: + stp_set_int_parameter_active(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE); + break; + case STP_PARAMETER_TYPE_RAW: + stp_set_raw_parameter_active(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE); + break; + case STP_PARAMETER_TYPE_FILE: + if (strcmp(opt->fast_desc->name, "PPDFile") != 0) + stp_set_file_parameter_active(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE); + break; + default: + break; + } + if (opt->checkbox) + g_signal_connect + (G_OBJECT(opt->checkbox), "toggled", + G_CALLBACK(set_controls_active), opt); + } + } +} + +static void +set_options_active(const char *omit) +{ + int i; + for (i = 0; i < current_option_count; i++) + { + option_t *opt = &(current_options[i]); + const stp_parameter_t *desc = opt->fast_desc; + GtkObject *adj; + if (omit && strcmp(omit, opt->fast_desc->name) == 0) + continue; + switch (desc->p_type) + { + case STP_PARAMETER_TYPE_STRING_LIST: + build_a_combo(opt); + break; + case STP_PARAMETER_TYPE_DOUBLE: + case STP_PARAMETER_TYPE_DIMENSION: + adj = opt->info.flt.adjustment; + if (adj) + { + if (opt->is_active && desc->p_level <= MAXIMUM_PARAMETER_LEVEL) + { + gtk_widget_show(GTK_WIDGET(SCALE_ENTRY_LABEL(adj))); + gtk_widget_show(GTK_WIDGET(SCALE_ENTRY_SCALE(adj))); + gtk_widget_show(GTK_WIDGET(SCALE_ENTRY_SPINBUTTON(adj))); + } + else + { + gtk_widget_hide(GTK_WIDGET(SCALE_ENTRY_LABEL(adj))); + gtk_widget_hide(GTK_WIDGET(SCALE_ENTRY_SCALE(adj))); + gtk_widget_hide(GTK_WIDGET(SCALE_ENTRY_SPINBUTTON(adj))); + } + } + break; + case STP_PARAMETER_TYPE_CURVE: + if (opt->is_active && desc->p_level <= MAXIMUM_PARAMETER_LEVEL) + { + gtk_widget_show(GTK_WIDGET(opt->info.curve.label)); + gtk_widget_show(GTK_WIDGET(opt->info.curve.button)); + } + else + { + gtk_widget_hide(GTK_WIDGET(opt->info.curve.label)); + gtk_widget_hide(GTK_WIDGET(opt->info.curve.button)); + gtk_widget_hide(GTK_WIDGET(opt->info.curve.dialog)); + } + case STP_PARAMETER_TYPE_BOOLEAN: + if (opt->is_active && desc->p_level <= MAXIMUM_PARAMETER_LEVEL) + { + gtk_widget_show(GTK_WIDGET(opt->info.bool.checkbox)); + } + else + { + gtk_widget_hide(GTK_WIDGET(opt->info.bool.checkbox)); + } + break; + default: + break; + } + if (opt->checkbox) + { + if (!(opt->is_active) || desc->p_level > MAXIMUM_PARAMETER_LEVEL) + gtk_widget_hide(GTK_WIDGET(opt->checkbox)); + else if (!(desc->is_mandatory)) + gtk_widget_show(GTK_WIDGET(opt->checkbox)); + } + } +} + +static void +color_button_callback(GtkWidget *widget, gpointer data) +{ + invalidate_preview_thumbnail(); + update_adjusted_thumbnail(); +} + +static void +create_top_level_structure(void) +{ + gchar *plug_in_name; + /* + * Create the main dialog + */ + + plug_in_name = g_strdup_printf (_("%s -- Print v%s"), + stpui_get_image_filename(), + VERSION " - " RELEASE_DATE); + + print_dialog = + stpui_dialog_new (plug_in_name, + GTK_WIN_POS_MOUSE, + TRUE, + + _("About"), about_callback, + NULL, NULL, NULL, FALSE, FALSE, + _("Print and\nSave Settings"), printandsave_callback, + NULL, NULL, NULL, FALSE, FALSE, + _("Save\nSettings"), save_callback, + NULL, NULL, NULL, FALSE, FALSE, + _("Print"), print_callback, + NULL, NULL, NULL, FALSE, FALSE, + _("Cancel"), gtk_widget_destroy, + NULL, (GObject *) 1, NULL, FALSE, TRUE, + + NULL); + + g_free (plug_in_name); + + g_signal_connect (G_OBJECT (print_dialog), "destroy", + G_CALLBACK (gtk_main_quit), NULL); + + /* + * Top-level containers + */ + + main_vbox = gtk_vbox_new (FALSE, 2); + gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (print_dialog)->vbox), main_vbox, + TRUE, TRUE, 0); + gtk_widget_show (main_vbox); + + main_hbox = gtk_hbox_new (FALSE, 4); + gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, TRUE, TRUE, 0); + gtk_widget_show (main_hbox); + + right_vbox = gtk_vbox_new (FALSE, 2); + gtk_box_pack_end (GTK_BOX (main_hbox), right_vbox, FALSE, FALSE, 0); + gtk_widget_show (right_vbox); + + notebook = gtk_notebook_new (); + gtk_box_pack_start (GTK_BOX (right_vbox), notebook, TRUE, TRUE, 0); + gtk_widget_show (notebook); +} + +static gint +drawing_area_resize_callback(GtkWidget *widget, GdkEventConfigure *event) +{ + preview_size_vert = event->height - 1; + preview_size_horiz = event->width - 1; + invalidate_preview_thumbnail(); + invalidate_frame(); + preview_update(); + return 1; +} + +static void +create_preview (void) +{ + GtkWidget *frame; + GtkWidget *event_box; + + frame = gtk_frame_new (_("Preview")); + gtk_box_pack_start (GTK_BOX (main_hbox), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + preview = (GtkDrawingArea *) gtk_drawing_area_new (); + gtk_drawing_area_size(preview, preview_size_horiz + 1, preview_size_vert +1); + g_signal_connect(G_OBJECT(preview), "configure_event", + G_CALLBACK(drawing_area_resize_callback), NULL); + event_box = gtk_event_box_new (); + gtk_container_add (GTK_CONTAINER (event_box), GTK_WIDGET (preview)); + gtk_container_add (GTK_CONTAINER (frame), event_box); + gtk_widget_show (event_box); + + g_signal_connect (G_OBJECT (preview), "expose_event", + G_CALLBACK (preview_expose), NULL); + g_signal_connect (G_OBJECT (preview), "button_press_event", + G_CALLBACK (preview_button_callback), NULL); + g_signal_connect (G_OBJECT (preview), "button_release_event", + G_CALLBACK (preview_button_callback), NULL); + g_signal_connect (G_OBJECT (preview), "motion_notify_event", + G_CALLBACK (preview_motion_callback), NULL); + gtk_widget_show (GTK_WIDGET (preview)); + + stpui_set_help_data + (event_box, + _("Position the image on the page.\n" + "Click and drag with the primary button to position the image.\n" + "Click and drag with the second button to move the image with finer precision; " + "each unit of motion moves the image one point (1/72\")\n" + "Click and drag with the third (middle) button to move the image in units of " + "the image size.\n" + "Holding down the shift key while clicking and dragging constrains the image to " + "only horizontal or vertical motion.\n" + "If you click another button while dragging the mouse, the image will return " + "to its original position.")); + + gtk_widget_set_events (GTK_WIDGET (preview), + GDK_EXPOSURE_MASK | GDK_BUTTON_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); +} + +static GtkWidget * +create_positioning_entry(GtkWidget *table, int hpos, int vpos, + const char *text, const char *help) +{ + return stpui_create_entry + (table, hpos, vpos, text, help, G_CALLBACK(position_callback)); +} + +static GtkWidget * +create_positioning_button(GtkWidget *box, int invalid, + const char *text, const char *help) +{ + GtkWidget *button = gtk_button_new_with_label(_(text)); + gtk_box_pack_start(GTK_BOX(box), button, FALSE, TRUE, 0); + gtk_widget_show(button); + stpui_set_help_data(button, help); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(position_button_callback), + (gpointer) invalid); + return button; +} + +static void +create_paper_size_frame(void) +{ + GtkWidget *frame; + GtkWidget *vbox; + GtkWidget *media_size_table; + GtkWidget *table; + int vpos = 0; + + frame = gtk_frame_new (_("Paper Size")); + gtk_box_pack_start (GTK_BOX (right_vbox), frame, FALSE, TRUE, 0); + gtk_widget_show (frame); + + vbox = gtk_vbox_new (FALSE, 2); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 4); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_widget_show (vbox); + + table = gtk_table_new (1, 1, FALSE); + gtk_container_add (GTK_CONTAINER (vbox), table); + gtk_widget_show (table); + + /* + * Media size combo box. + */ + + page_size_table = gtk_table_new(1, 1, FALSE); + gtk_widget_show (page_size_table); + gtk_table_attach_defaults(GTK_TABLE(table), page_size_table, + 0, 2, vpos, vpos + 1); + vpos++; + show_all_paper_sizes_button = + gtk_check_button_new_with_label(_("Show All Paper Sizes")); + gtk_table_attach_defaults + (GTK_TABLE(table), show_all_paper_sizes_button, 0, 2, vpos, vpos + 1); + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(show_all_paper_sizes_button), + stpui_show_all_paper_sizes); + g_signal_connect(G_OBJECT(show_all_paper_sizes_button), "toggled", + G_CALLBACK(show_all_paper_sizes_callback), NULL); + gtk_widget_show(show_all_paper_sizes_button); + vpos++; + + /* + * Custom media size entries + */ + + media_size_table = gtk_table_new (1, 1, FALSE); + stpui_table_attach_aligned(GTK_TABLE (table), 0, vpos++, _("Dimensions:"), + 0.0, 0.5, media_size_table, 1, TRUE); + gtk_table_set_col_spacings (GTK_TABLE (media_size_table), 4); + + custom_size_width = stpui_create_entry + (media_size_table, 0, 3, _("Width:"), + _("Width of the paper that you wish to print to"), + G_CALLBACK(custom_media_size_callback)); + + custom_size_height = stpui_create_entry + (media_size_table, 2, 3, _("Height:"), + _("Height of the paper that you wish to print to"), + G_CALLBACK(custom_media_size_callback)); + + vpos++; + auto_paper_size_button = + gtk_check_button_new_with_label(_("Automatic Paper Size")); + gtk_table_attach_defaults + (GTK_TABLE(table), auto_paper_size_button, 0, 2, vpos, vpos + 1); + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(auto_paper_size_button), FALSE); + g_signal_connect(G_OBJECT(auto_paper_size_button), "toggled", + G_CALLBACK(auto_paper_size_callback), NULL); +} + +static void +create_copy_number_frame(void) +{ + GtkWidget *frame; + GtkWidget *vbox; + GtkWidget *event_box; + GtkAdjustment *adj; + + frame = gtk_frame_new (_("Number of Copies")); + gtk_box_pack_start (GTK_BOX (right_vbox), frame, FALSE, TRUE, 0); + gtk_widget_show (frame); + + vbox = gtk_hbox_new (FALSE, 2); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 4); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_widget_show (vbox); + + event_box = gtk_event_box_new (); + gtk_container_add (GTK_CONTAINER (vbox), event_box); + stpui_set_help_data(event_box, + _("Select the number of copies to print; " + "a value between 1 and 100")); + gtk_widget_show (event_box); + + /* + * Number of Copies Spin Button + */ + + adj = (GtkAdjustment *) gtk_adjustment_new (1.0f, 1.0f, 100.0f, + 1.0f, 5.0f, 0.0f); + copy_count_spin_button = gtk_spin_button_new (adj, 0, 0); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (copy_count_spin_button), FALSE); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (copy_count_spin_button), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (copy_count_spin_button), + GTK_UPDATE_IF_VALID); + + g_signal_connect(G_OBJECT (adj), "value_changed", + G_CALLBACK (copy_count_callback), + NULL); + + gtk_container_add (GTK_CONTAINER (event_box), copy_count_spin_button); + gtk_widget_show(copy_count_spin_button); +} + +static void +create_positioning_frame (void) +{ + GtkWidget *frame; + GtkWidget *table; + GtkWidget *box; + GtkWidget *sep; + + frame = gtk_frame_new (_("Image Position")); + gtk_box_pack_start (GTK_BOX (right_vbox), frame, FALSE, TRUE, 0); + gtk_widget_show (frame); + + table = gtk_table_new (1, 1, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 2); + gtk_table_set_row_spacings (GTK_TABLE (table), 2); + gtk_container_set_border_width (GTK_CONTAINER (table), 4); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_widget_show (table); + + /* + * Orientation option menu. + */ + + orientation_menu = + stpui_option_menu_new (FALSE, + _("Auto"), orientation_callback, + (gpointer) ORIENT_AUTO, NULL, NULL, 0, + _("Portrait"), orientation_callback, + (gpointer) ORIENT_PORTRAIT, NULL, NULL, 0, + _("Landscape"), orientation_callback, + (gpointer) ORIENT_LANDSCAPE, NULL, NULL, 0, + _("Upside down"), orientation_callback, + (gpointer) ORIENT_UPSIDEDOWN, NULL, NULL, 0, + _("Seascape"), orientation_callback, + (gpointer) ORIENT_SEASCAPE, NULL, NULL, 0, + NULL); + stpui_set_help_data (orientation_menu, + _("Select the orientation: portrait, landscape, " + "upside down, or seascape (upside down landscape)")); + stpui_table_attach_aligned (GTK_TABLE (table), 0, 0, _("Orientation:"), + 1.0, 0.5, orientation_menu, 4, TRUE); + sep = gtk_hseparator_new (); + gtk_table_attach_defaults (GTK_TABLE (table), sep, 0, 6, 1, 2); + gtk_widget_show (sep); + + /* + * Position entries + */ + + left_entry = create_positioning_entry + (table, 0, 2, _("Left:"), + _("Distance from the left of the paper to the image")); +#if 0 + right_entry = create_positioning_entry + (table, 0, 3, _("Right:"), + _("Distance from the left of the paper to the right of the image")); +#endif + right_border_entry = create_positioning_entry + (table, 0, 4, _("Right:"), + _("Distance from the right of the paper to the image")); + top_entry = create_positioning_entry + (table, 3, 2, _("Top:"), + _("Distance from the top of the paper to the image")); +#if 0 + bottom_entry = create_positioning_entry + (table, 3, 3, _("Bottom:"), + _("Distance from the top of the paper to bottom of the image")); +#endif + bottom_border_entry = create_positioning_entry + (table, 3, 4, _("Bottom:"), + _("Distance from the bottom of the paper to the image")); + /* + * Center options + */ + + sep = gtk_hseparator_new (); + gtk_table_attach_defaults (GTK_TABLE (table), sep, 0, 6, 5, 6); + gtk_widget_show (sep); + + box = gtk_hbox_new (TRUE, 4); + stpui_table_attach_aligned (GTK_TABLE (table), 0, 7, _("Center:"), 0.5, 0.5, + box, 5, TRUE); + recenter_horizontal_button = create_positioning_button + (box, INVALID_LEFT, _("Horizontal"), + _("Center the image horizontally on the paper")); + recenter_button = create_positioning_button + (box, INVALID_LEFT | INVALID_TOP, _("Both"), + _("Center the image on the paper")); + recenter_vertical_button = create_positioning_button + (box, INVALID_TOP, _("Vertical"), + _("Center the image vertically on the paper")); +} + +static void +create_printer_dialog (void) +{ + GtkWidget *table; + GtkWidget *label; + GtkWidget *event_box; + GSList *group; + gint i; + stp_string_list_t *manufacturer_list = stp_string_list_create(); + + setup_dialog = stpui_dialog_new(_("Setup Printer"), + GTK_WIN_POS_MOUSE, TRUE, + _("OK"), setup_ok_callback, + NULL, NULL, NULL, TRUE, FALSE, + _("Cancel"), setup_cancel_callback, + NULL, (GObject *) 1, NULL, FALSE, TRUE, + NULL); + + /* + * Top-level table for dialog. + */ + + table = gtk_table_new (4, 4, FALSE); + gtk_container_set_border_width (GTK_CONTAINER (table), 6); + gtk_table_set_col_spacings (GTK_TABLE (table), 4); + gtk_table_set_row_spacing (GTK_TABLE (table), 0, 150); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (setup_dialog)->vbox), table, + TRUE, TRUE, 0); + gtk_widget_show (table); + + /* + * Printer driver option menu. + */ + + label = gtk_label_new (_("Printer Make:")); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 2, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + event_box = gtk_event_box_new (); + gtk_table_attach (GTK_TABLE (table), event_box, 2, 4, 0, 2, + GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0); + gtk_widget_show (event_box); + + stpui_set_help_data (event_box, _("Select the make of your printer")); + + manufacturer_crawler = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (manufacturer_crawler), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (event_box), manufacturer_crawler); + gtk_widget_show (manufacturer_crawler); + + manufacturer_clist = gtk_clist_new (1); + gtk_widget_set_usize (manufacturer_clist, 200, 0); + gtk_clist_set_selection_mode(GTK_CLIST(manufacturer_clist),GTK_SELECTION_SINGLE); + gtk_container_add (GTK_CONTAINER (manufacturer_crawler), manufacturer_clist); + gtk_widget_show (manufacturer_clist); + + g_signal_connect (G_OBJECT (manufacturer_clist), "select_row", + G_CALLBACK (manufacturer_callback), NULL); + + + label = gtk_label_new (_("Printer Model:")); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 4, 5, 0, 2, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + event_box = gtk_event_box_new (); + gtk_table_attach (GTK_TABLE (table), event_box, 5, 7, 0, 2, + GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0); + gtk_widget_show (event_box); + + stpui_set_help_data (event_box, _("Select your printer model")); + + printer_crawler = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (printer_crawler), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (event_box), printer_crawler); + gtk_widget_show (printer_crawler); + + printer_driver = gtk_clist_new (1); + gtk_widget_set_usize (printer_driver, 200, 0); + gtk_clist_set_selection_mode(GTK_CLIST(printer_driver),GTK_SELECTION_SINGLE); + gtk_container_add (GTK_CONTAINER (printer_crawler), printer_driver); + gtk_widget_show (printer_driver); + + g_signal_connect (G_OBJECT (printer_driver), "select_row", + G_CALLBACK (print_driver_callback), NULL); + + + for (i = 0; i < stp_printer_model_count (); i ++) + { + const stp_printer_t *the_printer = stp_get_printer_by_index (i); + + if (strcmp(stp_printer_get_long_name (the_printer), "") != 0 && + strcmp(stp_printer_get_family(the_printer), "raw") != 0) + { + const gchar *make = stp_printer_get_manufacturer(the_printer); + if (! stp_string_list_is_present(manufacturer_list, make)) + stp_string_list_add_string(manufacturer_list, make, make); + } + } + + for (i = 0; i < stp_string_list_count(manufacturer_list); i++) + { + const stp_param_string_t *param = + stp_string_list_param(manufacturer_list, i); + gchar *xname = g_strdup(param->name); + gtk_clist_insert(GTK_CLIST(manufacturer_clist), i, &xname); + gtk_clist_set_row_data_full(GTK_CLIST(manufacturer_clist), i, xname, + g_free); + } + stp_string_list_destroy(manufacturer_list); + gtk_clist_sort(GTK_CLIST(manufacturer_clist)); + build_printer_driver_clist(); + + /* + * PPD file. + */ + + ppd_label = gtk_label_new (_("PPD File:")); + gtk_misc_set_alignment (GTK_MISC (ppd_label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (table), ppd_label, 1, 2, 3, 4, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (ppd_label); + + ppd_box = gtk_hbox_new (FALSE, 8); + gtk_table_attach (GTK_TABLE (table), ppd_box, 2, 7, 3, 4, + GTK_FILL, GTK_FILL, 0, 0); + + ppd_file = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (ppd_box), ppd_file, TRUE, TRUE, 0); + gtk_widget_show (ppd_file); + + stpui_set_help_data(ppd_file,_("Enter the correct PPD filename for your printer")); + + ppd_button = gtk_button_new_with_label (_("Browse")); + gtk_misc_set_padding (GTK_MISC (GTK_BIN (ppd_button)->child), 2, 0); + gtk_box_pack_start (GTK_BOX (ppd_box), ppd_button, FALSE, FALSE, 0); + gtk_widget_show (ppd_button); + gtk_widget_show (ppd_box); + + stpui_set_help_data(ppd_button, + _("Choose the correct PPD filename for your printer")); + g_signal_connect (G_OBJECT (ppd_button), "clicked", + G_CALLBACK (ppd_browse_callback), NULL); + + /* + * Print command. + */ + + group = NULL; + for (i = 0; i < command_options_count; i++) + group = stpui_create_radio_button(&(command_options[i]), group, table, + 0, i > 0 ? i + 5 : i + 4, + G_CALLBACK(command_type_callback)); + + standard_cmd_entry = gtk_entry_new(); + gtk_table_attach (GTK_TABLE (table), standard_cmd_entry, 2, 7, 5, 6, + GTK_FILL, GTK_FILL, 0, 0); + gtk_entry_set_editable(GTK_ENTRY(standard_cmd_entry), FALSE); + gtk_widget_set_sensitive(standard_cmd_entry, FALSE); + gtk_widget_show (standard_cmd_entry); + + queue_combo = gtk_combo_new (); + event_box = gtk_event_box_new (); + gtk_container_add (GTK_CONTAINER (event_box), queue_combo); + gtk_widget_show (queue_combo); + gtk_widget_show (event_box); + build_queue_combo(); + + stpui_set_help_data(event_box, + _("Select the name of the output queue (not the type, " + "or model, of printer) that you wish to print to")); + label = gtk_label_new(_("Printer Queue:")); + gtk_widget_show(label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 4, 5, + GTK_FILL, GTK_FILL, 0, 0); + gtk_table_attach (GTK_TABLE (table), event_box, 3, 7, 4, 5, + GTK_FILL, GTK_FILL, 0, 0); + + custom_command_entry = gtk_entry_new (); + gtk_table_attach (GTK_TABLE (table), custom_command_entry, 2, 7, 6, 7, + GTK_FILL, GTK_FILL, 0, 0); + g_signal_connect(G_OBJECT(custom_command_entry), "activate", + G_CALLBACK(setup_callback), NULL); + gtk_widget_set_sensitive(custom_command_entry, FALSE); + gtk_widget_show (custom_command_entry); + + stpui_set_help_data + (custom_command_entry, _("Enter the correct command to print to your printer. ")); + + file_entry = gtk_entry_new (); + gtk_table_attach (GTK_TABLE (table), file_entry, 2, 6, 7, 8, + GTK_FILL, GTK_FILL, 0, 0); + g_signal_connect(G_OBJECT(file_entry), "activate", + G_CALLBACK(setup_callback), NULL); + gtk_widget_show (file_entry); + + gtk_widget_set_sensitive(file_entry, FALSE); + stpui_set_help_data + (file_entry, _("Enter the file to print to. ")); + + file_button = gtk_button_new_with_label (_("Browse")); + + gtk_table_attach (GTK_TABLE (table), file_button, 6, 7, 7, 8, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (file_button); + + stpui_set_help_data(file_button, _("File to print to")); + g_signal_connect (G_OBJECT (file_button), "clicked", + G_CALLBACK (file_browse_callback), NULL); + + /* + * Output file selection dialog. + */ + + file_browser = gtk_file_selection_new (_("Print To File")); + + g_signal_connect + (G_OBJECT (GTK_FILE_SELECTION (file_browser)->ok_button), "clicked", + G_CALLBACK (file_ok_callback), NULL); + g_signal_connect + (G_OBJECT (GTK_FILE_SELECTION (file_browser)->cancel_button), "clicked", + G_CALLBACK (file_cancel_callback), NULL); + + /* + * PPD file selection dialog. + */ + + ppd_browser = gtk_file_selection_new (_("PPD File")); + gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (ppd_browser)); + + g_signal_connect + (G_OBJECT (GTK_FILE_SELECTION (ppd_browser)->ok_button), "clicked", + G_CALLBACK (ppd_ok_callback), NULL); + g_signal_connect_object + (G_OBJECT (GTK_FILE_SELECTION (ppd_browser)->cancel_button), "clicked", + G_CALLBACK (gtk_widget_hide), G_OBJECT (ppd_browser), G_CONNECT_SWAPPED); +} + +static void +create_new_printer_dialog (void) +{ + GtkWidget *table; + + new_printer_dialog = + stpui_dialog_new (_("Define New Printer"), + GTK_WIN_POS_MOUSE, FALSE, + _("OK"), new_printer_ok_callback, + NULL, NULL, NULL, TRUE, FALSE, + _("Cancel"), gtk_widget_hide, + NULL, (GObject *) 1, NULL, FALSE, TRUE, + NULL); + + table = gtk_table_new (1, 1, FALSE); + gtk_container_set_border_width (GTK_CONTAINER (table), 6); + gtk_table_set_col_spacings (GTK_TABLE (table), 4); + gtk_table_set_row_spacings (GTK_TABLE (table), 8); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (new_printer_dialog)->vbox), table, + FALSE, FALSE, 0); + gtk_widget_show (table); + + new_printer_entry = gtk_entry_new (); + gtk_entry_set_max_length (GTK_ENTRY (new_printer_entry), 127); + stpui_table_attach_aligned(GTK_TABLE (table), 0, 0, _("Printer Name:"), 1.0, + 0.5, new_printer_entry, 1, TRUE); + + stpui_set_help_data(new_printer_entry, + _("Enter the name you wish to give this logical printer")); + g_signal_connect (G_OBJECT (new_printer_entry), "activate", + G_CALLBACK (new_printer_ok_callback), NULL); +} + +static void +create_about_dialog (void) +{ + GtkWidget *label; + about_dialog = + stpui_dialog_new (_("About Gutenprint " PLUG_IN_VERSION), + GTK_WIN_POS_MOUSE, FALSE, + _("OK"), gtk_widget_hide, + NULL, (GObject *) 1, NULL, TRUE, TRUE, + NULL); + + label = gtk_label_new + (_("Gutenprint Version " PLUG_IN_VERSION "\n" + "\n" + "Copyright (C) 1997-2003 Michael Sweet, Robert Krawitz,\n" + "and the rest of the Gutenprint Development Team.\n" + "\n" + "Please visit our web site at http://gimp-print.sourceforge.net.\n" + "\n" + "This program is free software; you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation; either version 2 of the License, or\n" + "(at your option) any later version.\n" + "\n" + "This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n" + "\n" + "You should have received a copy of the GNU General Public License\n" + "along with this program; if not, write to the Free Software\n" + "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 " + "USA\n")); + + gtk_misc_set_padding (GTK_MISC (label), 12, 4); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (about_dialog)->vbox), label, + FALSE, FALSE, 0); + gtk_widget_show (label); +} + +static void +create_printer_settings_frame (void) +{ + GtkWidget *table; + GtkWidget *sep; + GtkWidget *printer_hbox; + GtkWidget *button; + GtkWidget *event_box; + GtkWidget *scrolled_window; + gint vpos = 0; + + create_printer_dialog (); + create_about_dialog (); + create_new_printer_dialog (); + + table = gtk_table_new (1, 1, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 2); + gtk_table_set_row_spacings (GTK_TABLE (table), 2); + gtk_container_set_border_width (GTK_CONTAINER (table), 4); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), table, + gtk_label_new (_("Printer Settings"))); + gtk_widget_show (table); + + /* + * Printer option menu. + */ + + printer_combo = gtk_combo_new (); + event_box = gtk_event_box_new (); + gtk_container_add (GTK_CONTAINER (event_box), printer_combo); + gtk_widget_show (printer_combo); + + stpui_set_help_data(event_box, + _("Select the name of the printer (not the type, " + "or model, of printer) that you wish to print to")); + stpui_table_attach_aligned(GTK_TABLE (table), 0, vpos++, _("Printer Name:"), + 0.0, 0.5, event_box, 1, TRUE); + printer_model_label = gtk_label_new (""); + stpui_table_attach_aligned(GTK_TABLE (table), 0, vpos++, _("Printer Model:"), + 0.0, 0.0, printer_model_label, 1, TRUE); + printer_hbox = gtk_hbox_new (TRUE, 4); + gtk_table_attach (GTK_TABLE (table), printer_hbox, + 1, 4, vpos, vpos + 1, GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0); + vpos += 2; + gtk_widget_show (printer_hbox); + + /* + * Setup printer button + */ + + button = gtk_button_new_with_label (_("Setup Printer...")); + stpui_set_help_data(button, + _("Choose the printer model, PPD file, and command " + "that is used to print to this printer")); + gtk_misc_set_padding (GTK_MISC (GTK_BIN (button)->child), 2, 0); + gtk_box_pack_start (GTK_BOX (printer_hbox), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + g_signal_connect (G_OBJECT (button), "clicked", + G_CALLBACK (setup_open_callback), NULL); + + /* + * New printer button + */ + + button = gtk_button_new_with_label (_("New Printer...")); + stpui_set_help_data (button, _("Define a new logical printer. This can be used to " + "name a collection of settings that you wish to " + "remember for future use.")); + gtk_box_pack_start (GTK_BOX (printer_hbox), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + g_signal_connect (G_OBJECT (button), "clicked", + G_CALLBACK (new_printer_open_callback), NULL); + + sep = gtk_hseparator_new (); + gtk_table_attach (GTK_TABLE (table), sep, 0, 5, vpos, vpos + 1, + GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (sep); + vpos++; + + printer_features_table = gtk_table_new(1, 1, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (printer_features_table), 2); + gtk_table_set_row_spacings (GTK_TABLE (printer_features_table), 0); + gtk_widget_show (printer_features_table); + + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), + printer_features_table); + gtk_table_attach_defaults(GTK_TABLE(table), scrolled_window, + 0, 6, vpos, vpos + 1); + gtk_widget_show(scrolled_window); +} + +static void +create_scaling_frame (void) +{ + GtkWidget *frame; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *table; + GtkWidget *box; + GtkWidget *label; + GtkWidget *event_box; + GtkWidget *sep; + GSList *group; + + frame = gtk_frame_new (_("Image Size")); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + hbox = gtk_hbox_new (FALSE, 2); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 4); + gtk_container_add (GTK_CONTAINER (frame), hbox); + gtk_widget_show (hbox); + + vbox = gtk_vbox_new (FALSE, 2); +/* gtk_container_set_border_width (GTK_CONTAINER (vbox), 4); */ + gtk_container_add (GTK_CONTAINER (hbox), vbox); + gtk_widget_show (vbox); + + table = gtk_table_new (1, 1, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 4); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); + gtk_widget_show (table); + + /* + * Create the scaling adjustment using percent. It doesn't really matter, + * since as soon as we call plist_callback at the end of initialization + * everything will be put right. + */ + scaling_adjustment = + stpui_scale_entry_new (GTK_TABLE (table), 0, 0, _("Scaling:"), 100, 75, + 100.0, minimum_image_percent, 100.0, + 1.0, 10.0, 1, TRUE, 0, 0, NULL); + stpui_set_adjustment_tooltip(scaling_adjustment, + _("Set the scale (size) of the image")); + g_signal_connect (G_OBJECT (scaling_adjustment), "value_changed", + G_CALLBACK (scaling_update), NULL); + + box = gtk_hbox_new (FALSE, 4); + gtk_box_pack_start (GTK_BOX (vbox), box, TRUE, TRUE, 0); + gtk_widget_show (box); + + /* + * The scale by percent/ppi toggles + */ + + table = gtk_table_new (1, 1, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 4); + gtk_box_pack_start (GTK_BOX (box), table, FALSE, FALSE, 0); + gtk_widget_show (table); + + event_box = gtk_event_box_new (); + gtk_table_attach (GTK_TABLE (table), event_box, 0, 1, 0, 1, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (event_box); + + label = gtk_label_new (_("Scale by:")); + gtk_container_add (GTK_CONTAINER (event_box), label); + gtk_widget_show (label); + + stpui_set_help_data(event_box, + _("Select whether scaling is measured as percent of " + "available page size or number of output dots per inch")); + + scaling_percent = gtk_radio_button_new_with_label (NULL, _("Percent")); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (scaling_percent)); + stpui_table_attach_aligned(GTK_TABLE (table), 0, 0, NULL, 0.5, 0.5, + scaling_percent, 2, TRUE); + + stpui_set_help_data(scaling_percent, _("Scale the print to the size of the page")); + g_signal_connect (G_OBJECT (scaling_percent), "toggled", + G_CALLBACK (scaling_callback), NULL); + + scaling_ppi = gtk_radio_button_new_with_label (group, _("PPI")); + stpui_table_attach_aligned(GTK_TABLE (table), 2, 0, NULL, 0.5, 0.5, + scaling_ppi, 1, TRUE); + + stpui_set_help_data(scaling_ppi, + _("Scale the print to the number of dots per inch")); + g_signal_connect (G_OBJECT (scaling_ppi), "toggled", + G_CALLBACK (scaling_callback), NULL); + + sep = gtk_vseparator_new (); + gtk_box_pack_start (GTK_BOX (hbox), sep, FALSE, FALSE, 8); + gtk_widget_show (sep); + + /* + * The width/height enries + */ + + table = gtk_table_new (1, 1, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 2); + gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0); + gtk_widget_show (table); + + width_entry = create_positioning_entry + (table, 0, 0, _("Width:"), _("Set the width of the print")); + height_entry = create_positioning_entry + (table, 0, 1, _("Height:"), _("Set the height of the print")); + + /* + * The "image size" button + */ + + scaling_image = gtk_button_new_with_label (_("Use Original\nImage Size")); + gtk_misc_set_padding (GTK_MISC (GTK_BIN (scaling_image)->child), 2, 2); + gtk_box_pack_end (GTK_BOX (hbox), scaling_image, FALSE, FALSE, 0); + gtk_widget_show (scaling_image); + + stpui_set_help_data(scaling_image, + _("Set the print size to the size of the image")); + g_signal_connect (G_OBJECT (scaling_image), "clicked", + G_CALLBACK (scaling_callback), NULL); +} + +/* + * create_color_adjust_window (void) + * + * NOTES: + * creates the color adjuster popup, allowing the user to adjust brightness, + * contrast, saturation, etc. + */ +static void +create_color_adjust_window (void) +{ + GtkWidget *table; + GtkWidget *label; + GtkWidget *event_box; + GtkWidget *scrolled_window; + gint x, y; /* Window dimensions */ + + initialize_thumbnail(); + + color_adjust_dialog = + stpui_dialog_new(_("Print Color Adjust"), + GTK_WIN_POS_MOUSE, TRUE, + + _("Set Defaults"), set_color_defaults, + NULL, NULL, NULL, FALSE, FALSE, + _("Close"), gtk_widget_hide, + NULL, (GObject *) 1, NULL, TRUE, TRUE, + NULL); + + table = gtk_table_new (1, 1, FALSE); + gtk_container_set_border_width (GTK_CONTAINER (table), 6); + gtk_table_set_col_spacings (GTK_TABLE (table), 4); + gtk_table_set_row_spacings (GTK_TABLE (table), 0); +/* gtk_table_set_row_spacing (GTK_TABLE (table), 8, 6); */ + + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (color_adjust_dialog)->vbox), + table, TRUE, TRUE, 0); + gtk_widget_show (table); + + /* + * Drawing area for color swatch feedback display... + */ + + event_box = gtk_event_box_new (); + gtk_widget_show (GTK_WIDGET (event_box)); + gtk_table_attach (GTK_TABLE (table), GTK_WIDGET (event_box), + 0, 1, 0, 1, 0, 0, 0, 0); + + swatch = (GtkDrawingArea *) gtk_drawing_area_new (); + gtk_widget_set_events (GTK_WIDGET (swatch), GDK_EXPOSURE_MASK); + gtk_drawing_area_size (swatch, thumbnail_w, thumbnail_h); + gtk_container_add (GTK_CONTAINER (event_box), GTK_WIDGET (swatch)); + gtk_widget_show (GTK_WIDGET (swatch)); + + stpui_set_help_data (GTK_WIDGET (event_box), _("Image preview")); + g_signal_connect (G_OBJECT (swatch), "expose_event", + G_CALLBACK (redraw_color_swatch), + NULL); + + event_box = gtk_event_box_new (); + gtk_widget_show (GTK_WIDGET (event_box)); + gtk_table_attach (GTK_TABLE (table), GTK_WIDGET (event_box), + 1, 2, 0, 1, 0, 0, 0, 0); + + output_color_vbox = gtk_vbox_new(TRUE, 0); + gtk_container_add(GTK_CONTAINER(event_box), output_color_vbox); + gtk_widget_show(GTK_WIDGET(output_color_vbox)); + + label = gtk_label_new(_("View Output Channels:")); + gtk_box_pack_start(GTK_BOX(output_color_vbox), label, TRUE, TRUE, 0); + gtk_widget_show(GTK_WIDGET(label)); + + cyan_button = gtk_toggle_button_new_with_label(_("Cyan")); + gtk_box_pack_start(GTK_BOX(output_color_vbox), cyan_button, TRUE, TRUE, 0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cyan_button), TRUE); + gtk_widget_show(GTK_WIDGET(cyan_button)); + g_signal_connect (G_OBJECT (cyan_button), "toggled", + G_CALLBACK (color_button_callback), NULL); + + magenta_button = gtk_toggle_button_new_with_label(_("Magenta")); + gtk_box_pack_start(GTK_BOX(output_color_vbox), magenta_button, TRUE, TRUE,0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(magenta_button), TRUE); + gtk_widget_show(GTK_WIDGET(magenta_button)); + g_signal_connect (G_OBJECT (magenta_button), "toggled", + G_CALLBACK (color_button_callback), NULL); + + yellow_button = gtk_toggle_button_new_with_label(_("Yellow")); + gtk_box_pack_start(GTK_BOX(output_color_vbox), yellow_button, TRUE, TRUE, 0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(yellow_button), TRUE); + gtk_widget_show(GTK_WIDGET(yellow_button)); + g_signal_connect (G_OBJECT (yellow_button), "toggled", + G_CALLBACK (color_button_callback), NULL); + + black_button = gtk_toggle_button_new_with_label(_("Black")); + gtk_box_pack_start(GTK_BOX(output_color_vbox), black_button, TRUE, TRUE, 0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(black_button), TRUE); + gtk_widget_show(GTK_WIDGET(black_button)); + g_signal_connect (G_OBJECT (black_button), "toggled", + G_CALLBACK (color_button_callback), NULL); + + color_adjustment_table = gtk_table_new(1, 1, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (color_adjustment_table), 2); + gtk_table_set_row_spacings (GTK_TABLE (color_adjustment_table), 0); + gtk_container_set_border_width (GTK_CONTAINER (color_adjustment_table), 4); + gtk_widget_show (color_adjustment_table); + + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), + color_adjustment_table); + gtk_table_attach_defaults(GTK_TABLE(table), scrolled_window, + 0, 2, 1, 2); + gtk_widget_show(scrolled_window); + + /* The initial size request does not account for the + GtkScrolledWindow. */ + gtk_window_get_size(GTK_WINDOW(color_adjust_dialog), &x, &y); + gtk_window_set_default_size(GTK_WINDOW(color_adjust_dialog), x, y+300); +} + +static void +create_image_settings_frame (void) +{ + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *table; + GtkWidget *label; + GtkWidget *event_box; + GtkWidget *sep; + GSList *group; + gint i; + + create_color_adjust_window (); + + vbox = gtk_vbox_new (FALSE, 4); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 4); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, + gtk_label_new (_("Output"))); + gtk_widget_show (vbox); + + table = gtk_table_new (1, 1, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 4); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); + gtk_widget_show (table); + + event_box = gtk_event_box_new (); + gtk_table_attach (GTK_TABLE (table), event_box, 0, 1, 0, 1, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (event_box); + + /* + * Output type toggles. + */ + + table = gtk_table_new (1, 1, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 4); +/* gtk_table_set_row_spacing (GTK_TABLE (table), 2, 4); */ + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); + gtk_widget_show (table); + + event_box = gtk_event_box_new (); + gtk_table_attach (GTK_TABLE (table), event_box, 0, 1, 0, 1, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (event_box); + + label = gtk_label_new (_("Output Type:")); + gtk_container_add (GTK_CONTAINER (event_box), label); + gtk_widget_show (label); + + stpui_set_help_data(event_box, _("Select the desired output type")); + + group = NULL; + for (i = 0; i < output_type_count; i++) + group = stpui_create_radio_button(&(output_types[i]), group, table, 0, i, + G_CALLBACK(output_type_callback)); + + sep = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 0); + gtk_widget_show (sep); + + /* + * Color adjust button + */ + hbox = gtk_hbox_new (FALSE, 4); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); + gtk_widget_show(hbox); + label = gtk_label_new(""); + gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); + gtk_widget_show(label); + + adjust_color_button = gtk_button_new_with_label (_("Adjust Output...")); + gtk_misc_set_padding (GTK_MISC (GTK_BIN (adjust_color_button)->child), 4, 0); + gtk_box_pack_start (GTK_BOX (hbox), adjust_color_button, FALSE, FALSE, 0); + gtk_widget_show(adjust_color_button); + label = gtk_label_new(""); + gtk_box_pack_end(GTK_BOX(hbox), label, TRUE, TRUE, 0); + gtk_widget_show(label); + + stpui_set_help_data(adjust_color_button, + _("Adjust color balance, brightness, contrast, " + "saturation, and dither algorithm")); + g_signal_connect_object (G_OBJECT (adjust_color_button), "clicked", + G_CALLBACK (gtk_widget_show), + G_OBJECT (color_adjust_dialog), + G_CONNECT_SWAPPED); +} + +static void +create_units_frame (void) +{ + GtkWidget *vbox; + GtkWidget *table; + GtkWidget *label; + GtkWidget *event_box; + GSList *group; + gint i; + + units_hbox = gtk_hbox_new(FALSE, 0); + label = gtk_label_new(_("Size Units:")); + gtk_widget_show(label); + gtk_box_pack_start(GTK_BOX(units_hbox), label, TRUE, TRUE, 0); + units_label = gtk_label_new(_(" ")); + gtk_widget_show(units_label); + gtk_box_pack_start(GTK_BOX(units_hbox), units_label, TRUE, TRUE, 0); + gtk_widget_show(units_hbox); + + vbox = gtk_vbox_new (FALSE, 4); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 4); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, units_hbox); + gtk_widget_show (vbox); + + /* + * The units toggles + */ + + table = gtk_table_new (1, 1, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 4); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); + gtk_widget_show (table); + + event_box = gtk_event_box_new (); + gtk_table_attach (GTK_TABLE (table), event_box, 0, 1, 0, 1, + GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); + gtk_widget_show (event_box); + + label = gtk_label_new (_("Units:")); + gtk_container_add (GTK_CONTAINER (event_box), label); + gtk_widget_show (label); + + stpui_set_help_data(event_box, + _("Select the base unit of measurement for printing")); + + group = NULL; + for (i = 0; i < unit_count; i++) + { + unit_t *unit = &(units[i]); + unit->checkbox = gtk_radio_button_new_with_label(group, _(unit->name)); + group = gtk_radio_button_group(GTK_RADIO_BUTTON(unit->checkbox)); + stpui_table_attach_aligned(GTK_TABLE(table), i / 2, i % 2, NULL, 0.5, + 0.5, unit->checkbox, 1, TRUE); + stpui_set_help_data(unit->checkbox, _(unit->help)); + g_signal_connect(G_OBJECT(unit->checkbox), "toggled", + G_CALLBACK(unit_callback), (gpointer) i); + } +} + +/* + * create_main_window() + */ +static void +create_main_window (void) +{ + gint x, y; /* Window dimensions */ + + set_current_printer(); + manufacturer = stp_printer_get_manufacturer(stp_get_printer(pv->v)); + /* + * Create the various dialog components. Note that we're not + * actually initializing the values at this point; that will be done after + * the UI is fully created. + */ + + stpui_help_init(); + + create_top_level_structure (); + + create_preview (); + create_printer_settings_frame (); + create_units_frame(); + create_paper_size_frame(); + create_copy_number_frame(); + create_positioning_frame (); + create_scaling_frame (); + create_image_settings_frame (); + + /* + * Now actually set up the correct values in the dialog + */ + + do_update_thumbnail = 1; + build_printer_combo (); + plist_callback (NULL, (gpointer) stpui_plist_current); + update_adjusted_thumbnail (); + + /* The initial size request does not account for the + GtkScrolledWindow. */ + gtk_window_get_size(GTK_WINDOW(print_dialog), &x, &y); + gtk_window_set_default_size(GTK_WINDOW(print_dialog), x, y+80); + + gtk_widget_show (print_dialog); +} + +static void +set_entry_value(GtkWidget *entry, double value, int block) +{ + gchar s[255]; + gdouble unit_scaler = units[pv->unit].scale; + const gchar *format = units[pv->unit].format; + + g_snprintf(s, sizeof(s), format, value / unit_scaler); + if (block) + g_signal_handlers_block_matched (G_OBJECT (entry), + G_SIGNAL_MATCH_DATA, + 0, + 0, + NULL, + NULL, + NULL); + + gtk_entry_set_text (GTK_ENTRY (entry), s); + if (block) + g_signal_handlers_unblock_matched (G_OBJECT (entry), + G_SIGNAL_MATCH_DATA, + 0, + 0, + NULL, + NULL, + NULL); +} + +static void +reset_preview(void) +{ + if (!suppress_preview_reset) + { + stpui_enable_help(); + buttons_pressed = preview_active = 0; + } +} + +static void +invalidate_preview_thumbnail (void) +{ + preview_valid = FALSE; +} + +static void +invalidate_frame (void) +{ + frame_valid = FALSE; +} + +static void +compute_scaling_limits(gdouble *min_ppi_scaling, gdouble *max_ppi_scaling) +{ + if (auto_paper_size) + { + *min_ppi_scaling = + FINCH * (gdouble) image_width / (gdouble) printable_width; + } + else + { + gdouble min_ppi_scaling1 = + FINCH * (gdouble) image_width / (gdouble) printable_width; + gdouble min_ppi_scaling2 = + FINCH * (gdouble) image_height / (gdouble) printable_height; + + if (min_ppi_scaling1 > min_ppi_scaling2) + *min_ppi_scaling = min_ppi_scaling1; + else + *min_ppi_scaling = min_ppi_scaling2; + } + + *max_ppi_scaling = *min_ppi_scaling * 100 / minimum_image_percent; +} + +/* + * scaling_update() - Update the scaling scale using the slider. + */ +static void +scaling_update (GtkAdjustment *adjustment) +{ + reset_preview (); + + if (pv->scaling != adjustment->value) + { + invalidate_preview_thumbnail (); + if (GTK_TOGGLE_BUTTON (scaling_ppi)->active) + pv->scaling = -adjustment->value; + else + pv->scaling = adjustment->value; + + suppress_scaling_adjustment = TRUE; + preview_update (); + suppress_scaling_adjustment = FALSE; + } +} + +/* + * scaling_callback() - Update the scaling scale using radio buttons. + */ +static void +scaling_callback (GtkWidget *widget) +{ + gdouble max_ppi_scaling; + gdouble min_ppi_scaling; + gdouble current_scale; + + reset_preview (); + + if (suppress_scaling_callback) + return; + + compute_scaling_limits(&min_ppi_scaling, &max_ppi_scaling); + + if (widget == scaling_ppi) + { + if (! GTK_TOGGLE_BUTTON (scaling_ppi)->active) + return; + + GTK_ADJUSTMENT (scaling_adjustment)->lower = min_ppi_scaling; + GTK_ADJUSTMENT (scaling_adjustment)->upper = max_ppi_scaling; + + /* + * Compute the correct PPI to create an image of the same size + * as the one measured in percent + */ + current_scale = GTK_ADJUSTMENT (scaling_adjustment)->value; + GTK_ADJUSTMENT (scaling_adjustment)->value = + min_ppi_scaling / (current_scale / 100); + pv->scaling = 0.0; + } + else if (widget == scaling_percent) + { + gdouble new_percent; + + if (! GTK_TOGGLE_BUTTON (scaling_percent)->active) + return; + + current_scale = GTK_ADJUSTMENT (scaling_adjustment)->value; + GTK_ADJUSTMENT (scaling_adjustment)->lower = minimum_image_percent; + GTK_ADJUSTMENT (scaling_adjustment)->upper = 100.0; + + new_percent = 100 * min_ppi_scaling / current_scale; + + if (new_percent > 100) + new_percent = 100; + if (new_percent < minimum_image_percent) + new_percent = minimum_image_percent; + + GTK_ADJUSTMENT (scaling_adjustment)->value = new_percent; + pv->scaling = 0.0; + } + else if (widget == scaling_image) + { + gdouble yres = image_yres; + + invalidate_preview_thumbnail (); + + GTK_ADJUSTMENT (scaling_adjustment)->lower = min_ppi_scaling; + GTK_ADJUSTMENT (scaling_adjustment)->upper = max_ppi_scaling; + + if (yres < min_ppi_scaling) + yres = min_ppi_scaling; + if (yres > max_ppi_scaling) + yres = max_ppi_scaling; + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scaling_ppi), TRUE); + GTK_ADJUSTMENT (scaling_adjustment)->value = yres; + pv->scaling = 0.0; + } + + if (widget == scaling_ppi || widget == scaling_percent) + suppress_preview_update++; + gtk_adjustment_changed (GTK_ADJUSTMENT (scaling_adjustment)); + gtk_adjustment_value_changed (GTK_ADJUSTMENT (scaling_adjustment)); + if (auto_paper_size) + set_media_size(stp_get_string_parameter(pv->v, "PageSize")); + if (widget == scaling_ppi || widget == scaling_percent) + suppress_preview_update--; +} + +/**************************************************************************** + * + * plist_build_combo + * + ****************************************************************************/ +static void +plist_build_combo (GtkWidget *combo, /* I - Combo widget */ + GtkWidget *label, + stp_string_list_t *items, /* I - Menu items */ + int active, + const gchar *cur_item, /* I - Current item */ + const gchar *def_value, /* I - default item */ + GCallback callback, /* I - Callback */ + gint *callback_id, /* IO - Callback ID (init to -1) */ + int (*check_func)(const char *string), + gpointer data) +{ + gint i; /* Looping var */ + GList *list = 0; + gint num_items = 0; + GtkEntry *entry = GTK_ENTRY (GTK_COMBO (combo)->entry); + + if (check_func && items) + { + stp_string_list_t *new_items = stp_string_list_create(); + num_items = stp_string_list_count(items); + for (i = 0; i < num_items; i++) + { + stp_param_string_t *param = stp_string_list_param(items, i); + if ((*check_func)(param->name)) + stp_string_list_add_string(new_items, param->name, param->text); + } + items = new_items; + } + + if (items) + num_items = stp_string_list_count(items); + + if (*callback_id != -1) + g_signal_handler_disconnect (G_OBJECT (entry), *callback_id); + gtk_entry_set_editable (entry, FALSE); + + if (!active || num_items == 0) + { + list = g_list_append (list, _("Standard")); + gtk_combo_set_popdown_strings (GTK_COMBO (combo), list); + *callback_id = -1; + gtk_widget_set_sensitive (combo, FALSE); + gtk_widget_hide (combo); + if (label) + gtk_widget_hide(label); + if (check_func && items) + stp_string_list_destroy(items); + return; + } + + for (i = 0; i < num_items; i ++) + list = g_list_append(list, g_strdup(stp_string_list_param(items, i)->text)); + + gtk_combo_set_popdown_strings (GTK_COMBO (combo), list); + + for (i = 0; i < num_items; i ++) + if (strcmp(stp_string_list_param(items, i)->name, cur_item) == 0) + break; + + if (i >= num_items && def_value) + for (i = 0; i < num_items; i ++) + if (strcmp(stp_string_list_param(items, i)->name, def_value) == 0) + break; + + if (i >= num_items) + i = 0; + + gtk_entry_set_text (entry, stp_string_list_param(items, i)->text); + + gtk_combo_set_value_in_list (GTK_COMBO (combo), TRUE, FALSE); + gtk_widget_set_sensitive (combo, TRUE); + gtk_widget_show (combo); + if (label) + gtk_widget_show(label); + + *callback_id = g_signal_connect (G_OBJECT (entry), "changed", callback, + data); + if (check_func && items) + stp_string_list_destroy(items); +} + +void +stpui_set_image_dimensions(gint width, gint height) +{ + image_true_width = width; + image_true_height = height; +} + +void +stpui_set_image_resolution(gdouble xres, gdouble yres) +{ + image_xres = xres; + image_yres = yres; +} + +gint +stpui_compute_orientation(void) +{ + if (auto_paper_size || + (printable_width >= printable_height && + image_true_width >= image_true_height) || + (printable_height >= printable_width && + image_true_height >= image_true_width)) + return ORIENT_PORTRAIT; + else + return ORIENT_LANDSCAPE; +} + +static void +set_orientation(int orientation) +{ + pv->orientation = orientation; + if (orientation == ORIENT_AUTO) + orientation = stpui_compute_orientation(); + physical_orientation = orientation; + switch (orientation) + { + case ORIENT_PORTRAIT: + case ORIENT_UPSIDEDOWN: + image_height = image_true_height; + image_width = image_true_width; + preview_thumbnail_h = thumbnail_h; + preview_thumbnail_w = thumbnail_w; + break; + case ORIENT_LANDSCAPE: + case ORIENT_SEASCAPE: + image_height = image_true_width; + image_width = image_true_height; + preview_thumbnail_h = thumbnail_w; + preview_thumbnail_w = thumbnail_h; + break; + } + update_adjusted_thumbnail(); +} + +static void +position_button_callback(GtkWidget *widget, gpointer data) +{ + reset_preview(); + pv->invalid_mask |= (gint) data; + preview_update (); +} + +/* + * position_callback() - callback for position entry widgets + */ +static void +position_callback (GtkWidget *widget) +{ + gdouble new_printed_value = atof (gtk_entry_get_text (GTK_ENTRY (widget))); + gint new_value = SCALE(new_printed_value, units[pv->unit].scale); + + reset_preview (); + suppress_preview_update++; + + if (widget == top_entry) + stp_set_top(pv->v, new_value); +/* + else if (widget == bottom_entry) + stp_set_top(pv->v, new_value - print_height); +*/ + else if (widget == bottom_border_entry) + stp_set_top (pv->v, paper_height - print_height - new_value); + else if (widget == left_entry) + stp_set_left (pv->v, new_value); +/* + else if (widget == right_entry) + stp_set_left(pv->v, new_value - print_width); +*/ + else if (widget == right_border_entry) + stp_set_left (pv->v, paper_width - print_width - new_value); + else if (widget == width_entry || widget == height_entry) + { + gboolean was_percent = (pv->scaling >= 0); + if (pv->scaling >= 0) + { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scaling_ppi), TRUE); + scaling_callback (scaling_ppi); + } + if (widget == width_entry) + GTK_ADJUSTMENT (scaling_adjustment)->value = + ((gdouble) image_width) / (new_value / FINCH); + else + GTK_ADJUSTMENT (scaling_adjustment)->value = + ((gdouble) image_height) / (new_value / FINCH); + gtk_adjustment_value_changed (GTK_ADJUSTMENT (scaling_adjustment)); + if (was_percent) + { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(scaling_percent),TRUE); + gtk_adjustment_value_changed(GTK_ADJUSTMENT (scaling_adjustment)); + } + } + + suppress_preview_update--; + preview_update (); +} + +static void +set_adjustment_active(option_t *opt, gboolean active, gboolean do_toggle) +{ + GtkObject *adj = opt->info.flt.adjustment; + if (do_toggle) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(opt->checkbox), active); + gtk_widget_set_sensitive + (GTK_WIDGET (SCALE_ENTRY_LABEL (adj)), active); + gtk_widget_set_sensitive + (GTK_WIDGET (SCALE_ENTRY_SCALE (adj)), active); + gtk_widget_set_sensitive + (GTK_WIDGET (SCALE_ENTRY_SPINBUTTON (adj)), active); +} + +static void +set_combo_active(option_t *opt, gboolean active, gboolean do_toggle) +{ + if (do_toggle) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(opt->checkbox), active); + gtk_widget_set_sensitive(GTK_WIDGET(opt->info.list.combo), active); + gtk_widget_set_sensitive(GTK_WIDGET(opt->info.list.label), active); +} + +static void +set_curve_active(option_t *opt, gboolean active, gboolean do_toggle) +{ + if (do_toggle) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(opt->checkbox), active); + gtk_widget_set_sensitive(GTK_WIDGET(opt->info.curve.button), active); + gtk_widget_set_sensitive(GTK_WIDGET(opt->info.curve.label), active); + if (active) + { + if (opt->info.curve.is_visible) + gtk_widget_show(GTK_WIDGET(opt->info.curve.dialog)); + } + else + gtk_widget_hide(GTK_WIDGET(opt->info.curve.dialog)); +} + +static void +set_bool_active(option_t *opt, gboolean active, gboolean do_toggle) +{ + if (do_toggle) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(opt->checkbox), active); + gtk_widget_set_sensitive(GTK_WIDGET(opt->info.bool.checkbox), active); +} + +static void +do_color_updates (void) +{ + int i; + for (i = 0; i < current_option_count; i++) + { + option_t *opt = &(current_options[i]); + if (opt->fast_desc->p_level <= MAXIMUM_PARAMETER_LEVEL) + { + switch (opt->fast_desc->p_type) + { + case STP_PARAMETER_TYPE_DOUBLE: + if (stp_check_float_parameter(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE)) + gtk_adjustment_set_value + (GTK_ADJUSTMENT(opt->info.flt.adjustment), + stp_get_float_parameter(pv->v, opt->fast_desc->name)); + if (stp_check_float_parameter(pv->v, opt->fast_desc->name, + STP_PARAMETER_ACTIVE) || + opt->fast_desc->is_mandatory) + set_adjustment_active(opt, TRUE, TRUE); + else + set_adjustment_active(opt, FALSE, TRUE); + break; + case STP_PARAMETER_TYPE_DIMENSION: + if (stp_check_dimension_parameter(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE)) + { + gdouble unit_scaler = units[pv->unit].scale; + gtk_adjustment_set_value + (GTK_ADJUSTMENT(opt->info.flt.adjustment), + (stp_get_dimension_parameter(pv->v, opt->fast_desc->name) / + unit_scaler)); + } + if (stp_check_dimension_parameter(pv->v, opt->fast_desc->name, + STP_PARAMETER_ACTIVE) || + opt->fast_desc->is_mandatory) + set_adjustment_active(opt, TRUE, TRUE); + else + set_adjustment_active(opt, FALSE, TRUE); + break; + case STP_PARAMETER_TYPE_CURVE: + if (stp_check_curve_parameter(pv->v, opt->fast_desc->name, + STP_PARAMETER_ACTIVE) || + opt->fast_desc->is_mandatory) + set_curve_active(opt, TRUE, TRUE); + else + set_curve_active(opt, FALSE, TRUE); + break; + case STP_PARAMETER_TYPE_STRING_LIST: + if (strcmp(opt->fast_desc->name, "PageSize") == 0) + build_page_size_combo(opt); + else if (stp_check_string_parameter(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE)) + plist_build_combo(opt->info.list.combo, opt->info.list.label, + opt->info.list.params, opt->is_active, + (stp_get_string_parameter + (pv->v, opt->fast_desc->name)), + opt->info.list.default_val, + G_CALLBACK(combo_callback), + &(opt->info.list.callback_id), + NULL, opt); + if (stp_check_string_parameter(pv->v, opt->fast_desc->name, + STP_PARAMETER_ACTIVE) || + opt->fast_desc->is_mandatory) + set_combo_active(opt, TRUE, TRUE); + else + set_combo_active(opt, FALSE, TRUE); + break; + case STP_PARAMETER_TYPE_BOOLEAN: + if (stp_check_boolean_parameter(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE)) + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(opt->info.bool.checkbox), + stp_get_boolean_parameter(pv->v, opt->fast_desc->name)); + if (stp_check_boolean_parameter(pv->v, opt->fast_desc->name, + STP_PARAMETER_ACTIVE) || + opt->fast_desc->is_mandatory) + set_bool_active(opt, TRUE, TRUE); + else + set_bool_active(opt, FALSE, TRUE); + break; + default: + break; + } + } + } + update_adjusted_thumbnail (); +} + +static void +update_options(void) +{ + gtk_widget_hide(page_size_table); + gtk_widget_hide(printer_features_table); + gtk_widget_hide(color_adjustment_table); + populate_options(pv->v); + populate_option_table(page_size_table, STP_PARAMETER_CLASS_CORE); + populate_option_table(printer_features_table, STP_PARAMETER_CLASS_FEATURE); + populate_option_table(color_adjustment_table, STP_PARAMETER_CLASS_OUTPUT); + gtk_widget_show(page_size_table); + gtk_widget_show(printer_features_table); + gtk_widget_show(color_adjustment_table); + set_options_active(NULL); +} + +static void +update_standard_print_command(void) +{ + char *label_text = + stpui_build_standard_print_command(pv, stp_get_printer(pv->v)); + gtk_entry_set_text(GTK_ENTRY(standard_cmd_entry), label_text); + g_free(label_text); +} + +static void +do_all_updates(void) +{ + gint i; + suppress_preview_update++; + set_orientation(pv->orientation); + invalidate_preview_thumbnail (); + preview_update (); + update_standard_print_command(); + + if (pv->scaling < 0) + { + gdouble tmp = -pv->scaling; + gdouble max_ppi_scaling; + gdouble min_ppi_scaling; + + compute_scaling_limits(&min_ppi_scaling, &max_ppi_scaling); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scaling_ppi), TRUE); + GTK_ADJUSTMENT (scaling_adjustment)->lower = min_ppi_scaling; + GTK_ADJUSTMENT (scaling_adjustment)->upper = max_ppi_scaling; + GTK_ADJUSTMENT (scaling_adjustment)->value = tmp; + gtk_adjustment_changed (GTK_ADJUSTMENT (scaling_adjustment)); + gtk_adjustment_value_changed (GTK_ADJUSTMENT (scaling_adjustment)); + } + else + { + gdouble tmp = pv->scaling; + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scaling_percent), TRUE); + GTK_ADJUSTMENT (scaling_adjustment)->lower = minimum_image_percent; + GTK_ADJUSTMENT (scaling_adjustment)->upper = 100.0; + GTK_ADJUSTMENT (scaling_adjustment)->value = tmp; + g_signal_emit_by_name (G_OBJECT(scaling_adjustment), "changed"); + g_signal_emit_by_name (G_OBJECT(scaling_adjustment), "value_changed"); + } + + for (i = 0; i < output_type_count; i++) + { + if (stp_get_string_parameter(pv->v, "PrintingMode") && + strcmp(output_types[i].value, + stp_get_string_parameter(pv->v, "PrintingMode")) == 0) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(output_types[i].button), + TRUE); + } + + /* + * Now get option parameters. + */ + + update_options(); + do_color_updates (); + + gtk_option_menu_set_history (GTK_OPTION_MENU (orientation_menu), + pv->orientation + 1); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(units[pv->unit].checkbox), + TRUE); + gtk_label_set_text(GTK_LABEL(units_label), units[pv->unit].name); + suppress_preview_update--; + preview_update (); +} + +static void +copy_count_callback(GtkAdjustment *adjustment, gpointer data) +{ + gint copy_count = (gint) adjustment->value; + stpui_plist_set_copy_count(pv, copy_count); + update_standard_print_command(); +} + +static void +auto_paper_size_callback(GtkWidget *widget, gpointer data) +{ + auto_paper_size = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(auto_paper_size_button)); + pv->auto_size_roll_feed_paper = auto_paper_size; + set_orientation(pv->orientation); + do_all_updates(); +} + +static void +setup_auto_paper_size(void) +{ + const stp_papersize_t *ps = + stp_get_papersize_by_name(stp_get_string_parameter(pv->v, "PageSize")); + if (ps->height == 0 && ps->width != 0) /* Implies roll feed */ + { + g_signal_handlers_block_matched (G_OBJECT(auto_paper_size_button), + G_SIGNAL_MATCH_DATA, + 0, + 0, + NULL, + NULL, + NULL); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(auto_paper_size_button), + pv->auto_size_roll_feed_paper); + gtk_widget_show(auto_paper_size_button); + g_signal_handlers_unblock_matched (G_OBJECT(auto_paper_size_button), + G_SIGNAL_MATCH_DATA, + 0, + 0, + NULL, + NULL, + NULL); + } + else + { + gtk_widget_hide(auto_paper_size_button); + auto_paper_size = 0; + } +} + +static void +queue_callback (GtkWidget *widget, + gpointer data) +{ + int i; + int count = stp_string_list_count(stpui_system_print_queues); + const gchar *result = + gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(queue_combo)->entry)); + for (i = 0; i < count; i++) + { + const stp_param_string_t *s = + stp_string_list_param(stpui_system_print_queues, i); + if (!strcmp(result, s->text)) + { + stpui_plist_set_queue_name(pv, s->name); + do_all_updates(); + return; + } + } +} + +static void +setup_callback (GtkWidget *widget) +{ + const gchar *new_value = gtk_entry_get_text (GTK_ENTRY (widget)); + + if (widget == custom_command_entry) + stpui_plist_set_custom_command(pv, new_value); + else if (widget == file_entry) + { + stpui_plist_set_output_filename(pv, new_value); + gtk_file_selection_set_filename + (GTK_FILE_SELECTION (file_browser), + gtk_entry_get_text (GTK_ENTRY (file_entry))); + } +} + +/* + * plist_callback() - Update the current system printer. + */ +static void +plist_callback (GtkWidget *widget, + gpointer data) +{ + gint i; + char *tmp; + stp_parameter_t desc; + + suppress_preview_update++; + invalidate_frame (); + invalidate_preview_thumbnail (); + reset_preview (); + + if (widget) + { + const gchar *result = + gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(printer_combo)->entry)); + + for (i = 0; i < stpui_plist_count; i++) + { + if (! strcmp (result, stp_string_list_param(printer_list, i)->text)) + { + stpui_plist_current = i; + break; + } + } + } + else + { + stpui_plist_current = (gint) data; + } + + set_current_printer(); + build_queue_combo(); + manufacturer = stp_printer_get_manufacturer(stp_get_printer(pv->v)); + build_printer_driver_clist(); + + if (strcmp(stp_get_driver(pv->v), "") != 0) + tmp_printer = stp_get_printer(pv->v); + + stp_describe_parameter(pv->v, "PrintingMode", &desc); + if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST) + { + if (!stp_string_list_is_present(desc.bounds.str, "Color")) + { + gtk_widget_set_sensitive (output_types[1].button, TRUE); + if (gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON (output_types[0].button)) == TRUE) + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON (output_types[1].button), TRUE); + gtk_widget_set_sensitive (output_types[0].button, FALSE); + } + else if (!stp_string_list_is_present(desc.bounds.str, "BW")) + { + gtk_widget_set_sensitive (output_types[0].button, TRUE); + if (gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON (output_types[1].button)) == TRUE) + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON (output_types[0].button), TRUE); + gtk_widget_set_sensitive (output_types[1].button, FALSE); + } + else + { + gtk_widget_set_sensitive (output_types[0].button, TRUE); + gtk_widget_set_sensitive (output_types[1].button, TRUE); + } + } + stp_parameter_description_destroy(&desc); + gtk_entry_set_text(GTK_ENTRY(file_entry), + stpui_plist_get_output_filename(pv)); + tmp = stpui_build_standard_print_command(pv, stp_get_printer(pv->v)); + gtk_entry_set_text(GTK_ENTRY(standard_cmd_entry), tmp); + stp_free(tmp); + gtk_entry_set_text(GTK_ENTRY(custom_command_entry), + stpui_plist_get_custom_command(pv)); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(copy_count_spin_button), + (gfloat) stpui_plist_get_copy_count(pv)); + do_all_updates(); + + setup_update (); + do_all_updates(); + suppress_preview_update--; + update_adjusted_thumbnail(); + preview_update (); +} + +static void +show_all_paper_sizes_callback(GtkWidget *widget, gpointer data) +{ + int i; + stpui_show_all_paper_sizes = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); + for (i = 0; i < current_option_count; i++) + { + option_t *option = &(current_options[i]); + if (option->fast_desc && + strcmp(option->fast_desc->name, "PageSize") == 0) + { + build_a_combo(option); + break; + } + } +} + +static void +custom_media_size_callback(GtkWidget *widget, + gpointer data) +{ + gint width_limit, height_limit; + gint min_width_limit, min_height_limit; + gdouble new_printed_value = atof(gtk_entry_get_text(GTK_ENTRY(widget))); + gint new_value = SCALE(new_printed_value, units[pv->unit].scale); + invalidate_frame (); + invalidate_preview_thumbnail (); + reset_preview (); + + stp_get_size_limit(pv->v, &width_limit, &height_limit, + &min_width_limit, &min_height_limit); + if (widget == custom_size_width) + { + if (new_value < min_width_limit) + new_value = min_width_limit; + else if (new_value > width_limit) + new_value = width_limit; + stp_set_page_width (pv->v, new_value); + } + else + { + if (new_value < min_height_limit) + new_value = min_height_limit; + else if (new_value > height_limit) + new_value = height_limit; + stp_set_page_height (pv->v, new_value); + } + set_entry_value (widget, new_value, 0); + preview_update (); +} + + +/* + * media_size_callback() - Update the current media size. + */ +static void +set_media_size(const gchar *new_media_size) +{ + static int setting_media_size = 0; + const stp_papersize_t *pap = stp_get_papersize_by_name (new_media_size); + + if (setting_media_size) + return; + setting_media_size++; + + if (pap) + { + gint size; + int old_width = stp_get_page_width(pv->v); + int old_height = stp_get_page_height(pv->v); + int need_preview_update = 0; + + if (! stpui_show_all_paper_sizes && + (pap->paper_unit == PAPERSIZE_METRIC_EXTENDED || + pap->paper_unit == PAPERSIZE_ENGLISH_EXTENDED)) + { + int i; + stp_parameter_t desc; + stp_describe_parameter(pv->v, "PageSize", &desc); + stp_set_string_parameter(pv->v, "PageSize", desc.deflt.str); + pap = stp_get_papersize_by_name(desc.deflt.str); + stp_parameter_description_destroy(&desc); + for (i = 0; i < current_option_count; i++) + { + option_t *option = &(current_options[i]); + if (option->fast_desc && + strcmp(option->fast_desc->name, "PageSize") == 0) + { + build_a_combo(option); + break; + } + } + } + + if (pap->width == 0) + { + int max_w, max_h, min_w, min_h; + stp_get_size_limit(pv->v, &max_w, &max_h, &min_w, &min_h); + size = old_width; + if (size < min_w) + size = min_w; + else if (size > max_w) + size = max_w; + gtk_widget_set_sensitive (GTK_WIDGET (custom_size_width), TRUE); + gtk_entry_set_editable (GTK_ENTRY (custom_size_width), TRUE); + } + else + { + size = pap->width; + gtk_widget_set_sensitive (GTK_WIDGET (custom_size_width), FALSE); + gtk_entry_set_editable (GTK_ENTRY (custom_size_width), FALSE); + } + if (size != old_width) + { + need_preview_update = 1; + set_entry_value (custom_size_width, size, 0); + stp_set_page_width (pv->v, size); + } + + setup_auto_paper_size(); + if (pap->height == 0) + { + int max_w, max_h, min_w, min_h; + stp_get_size_limit(pv->v, &max_w, &max_h, &min_w, &min_h); + if (auto_paper_size) + { + int l, r, b, t; + stp_set_page_height(pv->v, 0); + old_height = 0; + stp_get_imageable_area(pv->v, &l, &r, &b, &t); + gtk_widget_set_sensitive(GTK_WIDGET(custom_size_height), FALSE); + gtk_entry_set_editable(GTK_ENTRY(custom_size_height), FALSE); + size = print_height; + } + else + { + gtk_widget_set_sensitive (GTK_WIDGET (custom_size_height), TRUE); + gtk_entry_set_editable (GTK_ENTRY (custom_size_height), TRUE); + size = old_height; + } + if (size < min_h) + size = min_h; + else if (size > max_h) + size = max_h; + } + else + { + size = pap->height; + gtk_widget_set_sensitive(GTK_WIDGET (custom_size_height), FALSE); + gtk_entry_set_editable (GTK_ENTRY (custom_size_height), FALSE); + } + if (size != old_height) + { + need_preview_update = 1; + set_entry_value (custom_size_height, size, 0); + stp_set_page_height (pv->v, size); + } + if (need_preview_update) + { + invalidate_preview_thumbnail(); + invalidate_frame(); + preview_update(); + } + } + setting_media_size--; +} + +static gboolean +refresh_all_options(gpointer data) +{ + do_all_updates(); + do_all_updates(); /* Update twice to pick up cascading changes */ + return FALSE; +} + +static void +combo_callback(GtkWidget *widget, gpointer data) +{ + option_t *option = (option_t *)data; + const gchar *new_value = + stpui_combo_get_name(option->info.list.combo, option->info.list.params); + const gchar *value = + stp_get_string_parameter(pv->v, option->fast_desc->name); + if (value && new_value) + { + reset_preview(); + if (!value || strcmp(value, new_value) != 0) + { + invalidate_frame(); + invalidate_preview_thumbnail(); + stp_set_string_parameter(pv->v, option->fast_desc->name, new_value); + if (strcmp(option->fast_desc->name, "PageSize") == 0) + set_media_size(new_value); + g_idle_add(refresh_all_options, NULL); + if (option->fast_desc->p_class == STP_PARAMETER_CLASS_OUTPUT) + update_adjusted_thumbnail(); + preview_update(); + } + } +} + +/* + * orientation_callback() - Update the current media size. + */ +static void +orientation_callback (GtkWidget *widget, + gpointer data) +{ + reset_preview (); + + if (pv->orientation != (gint) data) + { + invalidate_preview_thumbnail (); + set_orientation((gint) data); + preview_update (); + } +} + +/* + * output_type_callback() - Update the current output type. + */ +static void +output_type_callback (GtkWidget *widget, + gpointer data) +{ + reset_preview (); + + if (GTK_TOGGLE_BUTTON (widget)->active) + { + if (strcmp((const char *) data, "BW") == 0) + gtk_widget_hide(output_color_vbox); + else + gtk_widget_show(output_color_vbox); + stp_set_string_parameter(pv->v, "PrintingMode", (const char *) data); + invalidate_preview_thumbnail (); + update_adjusted_thumbnail (); + set_options_active(NULL); + preview_update (); + do_all_updates(); + } +} + +static void +command_type_callback(GtkWidget *widget, gpointer data) +{ + if (strcmp((const char *) data, "Standard") == 0) + { + gtk_widget_set_sensitive(standard_cmd_entry, TRUE); + gtk_widget_set_sensitive(queue_combo, TRUE); + gtk_widget_set_sensitive(file_entry, FALSE); + gtk_entry_set_editable(GTK_ENTRY(file_entry), FALSE); + gtk_widget_set_sensitive(custom_command_entry, FALSE); + gtk_entry_set_editable(GTK_ENTRY(custom_command_entry), FALSE); + gtk_widget_hide(GTK_WIDGET(file_browser)); + gtk_widget_set_sensitive(file_button, FALSE); + gtk_widget_set_sensitive(copy_count_spin_button, TRUE); + stpui_plist_set_command_type(pv, COMMAND_TYPE_DEFAULT); + } + else if (strcmp((const char *) data, "Custom") == 0) + { + gtk_widget_set_sensitive(standard_cmd_entry, FALSE); + gtk_widget_set_sensitive(queue_combo, FALSE); + gtk_widget_set_sensitive(file_entry, FALSE); + gtk_entry_set_editable(GTK_ENTRY(file_entry), FALSE); + gtk_widget_set_sensitive(custom_command_entry, TRUE); + gtk_entry_set_editable(GTK_ENTRY(custom_command_entry), TRUE); + gtk_widget_hide(GTK_WIDGET(file_browser)); + gtk_widget_set_sensitive(file_button, FALSE); + gtk_widget_set_sensitive(copy_count_spin_button, FALSE); + stpui_plist_set_command_type(pv, COMMAND_TYPE_CUSTOM); + } + else if (strcmp((const char *) data, "File") == 0) + { + gtk_widget_set_sensitive(standard_cmd_entry, FALSE); + gtk_widget_set_sensitive(queue_combo, FALSE); + gtk_widget_set_sensitive(file_entry, TRUE); + gtk_entry_set_editable(GTK_ENTRY(file_entry), TRUE); + gtk_widget_set_sensitive(custom_command_entry, FALSE); + gtk_entry_set_editable(GTK_ENTRY(custom_command_entry), FALSE); + gtk_widget_set_sensitive(file_button, TRUE); + gtk_widget_set_sensitive(copy_count_spin_button, FALSE); + stpui_plist_set_command_type(pv, COMMAND_TYPE_FILE); + } +} + +static void +set_all_entry_values(void) +{ + set_entry_value (top_entry, (stp_get_top (pv->v)), 1); + set_entry_value (left_entry, (stp_get_left (pv->v)), 1); +/* + set_entry_value (bottom_entry, (top + stp_get_top(pv->v) + print_height), 1); +*/ + set_entry_value (bottom_border_entry, + (paper_height - (stp_get_top (pv->v) + print_height)), 1); +/* + set_entry_value (right_entry, (stp_get_left(pv->v) + print_width), 1); +*/ + set_entry_value (right_border_entry, + (paper_width - (stp_get_left (pv->v) + print_width)), 1); + set_entry_value (width_entry, print_width, 1); + set_entry_value (height_entry, print_height, 1); + set_entry_value (custom_size_width, stp_get_page_width (pv->v), 1); + set_entry_value (custom_size_height, stp_get_page_height (pv->v), 1); +} + +/* + * unit_callback() - Update the current unit. + */ +static void +unit_callback (GtkWidget *widget, + gpointer data) +{ + reset_preview (); + + if (GTK_TOGGLE_BUTTON (widget)->active) + { + pv->unit = (gint) data; + gtk_label_set_text(GTK_LABEL(units_label), units[pv->unit].name); + set_all_entry_values(); + update_options(); + do_color_updates(); + } +} + +static void +destroy_dialogs (void) +{ + int i; + gtk_widget_destroy (color_adjust_dialog); + gtk_widget_destroy (setup_dialog); + gtk_widget_destroy (print_dialog); + gtk_widget_destroy (new_printer_dialog); + gtk_widget_destroy (about_dialog); + for (i = 0; i < current_option_count; i++) + { + if (current_options[i].fast_desc->p_type == STP_PARAMETER_TYPE_CURVE && + current_options[i].info.curve.dialog) + gtk_widget_destroy(current_options[i].info.curve.dialog); + } +} + +static void +dialogs_set_sensitive (gboolean sensitive) +{ + int i; + gtk_widget_set_sensitive (color_adjust_dialog, sensitive); + gtk_widget_set_sensitive (setup_dialog, sensitive); + gtk_widget_set_sensitive (print_dialog, sensitive); + gtk_widget_set_sensitive (new_printer_dialog, sensitive); + gtk_widget_set_sensitive (about_dialog, sensitive); + for (i = 0; i < current_option_count; i++) + { + if (current_options[i].fast_desc->p_type == STP_PARAMETER_TYPE_CURVE && + current_options[i].info.curve.dialog) + gtk_widget_set_sensitive(current_options[i].info.curve.dialog, + sensitive); + } +} + +/* + * 'print_callback()' - Start the print. + */ +static void +print_callback (void) +{ + if (stpui_plist_get_command_type(pv) == COMMAND_TYPE_FILE && + strlen(stpui_plist_get_output_filename(pv)) == 0) + { + dialogs_set_sensitive (FALSE); + exit_after_file_ok = 1; + gtk_widget_show (file_browser); + } + else + { + runme = TRUE; + destroy_dialogs (); + } +} + +/* + * printandsave_callback() - + */ +static void +printandsave_callback (void) +{ + saveme = TRUE; + print_callback(); +} + +static void +about_callback (void) +{ + gtk_widget_show (about_dialog); +} + +/* + * save_callback() - save settings, don't destroy dialog + */ +static void +save_callback (void) +{ + reset_preview (); + stpui_printrc_save (); +} + +/* + * setup_update() - update widgets in the setup dialog + */ +static void +setup_update (void) +{ + GtkAdjustment *adjustment; + gint idx = 0; + gint i; + gchar *tmp; + const char *ppd_file_name = stp_get_file_parameter(pv->v, "PPDFile"); + + for (i = 0; i < GTK_CLIST(manufacturer_clist)->rows; i++) + { + (void) gtk_clist_get_text(GTK_CLIST(manufacturer_clist), i, 0, &tmp); + if (tmp && strcmp(manufacturer, tmp) == 0) + { + idx = i; + break; + } + } + gtk_clist_select_row(GTK_CLIST(manufacturer_clist), idx, 0); + + idx = stp_get_printer_index_by_driver (stp_get_driver (pv->v)); + + idx = gtk_clist_find_row_from_data(GTK_CLIST(printer_driver), + (gpointer) idx); +/* + if (idx >= 0) + idx = 0; +*/ + gtk_clist_select_row (GTK_CLIST (printer_driver), idx, 0); + gtk_label_set_text (GTK_LABEL (printer_model_label), + gettext (stp_printer_get_long_name (tmp_printer))); + + if (ppd_file_name) + gtk_entry_set_text (GTK_ENTRY (ppd_file), ppd_file_name); + else + gtk_entry_set_text (GTK_ENTRY (ppd_file), ""); + + if (stp_parameter_find_in_settings(pv->v, "PPDFile")) + { + gtk_widget_show (ppd_box); + gtk_widget_show (ppd_label); + } + else + { + gtk_widget_hide (ppd_box); + gtk_widget_hide (ppd_label); + } + gtk_entry_set_text (GTK_ENTRY (custom_command_entry), + stpui_plist_get_custom_command (pv)); + + adjustment = GTK_CLIST (printer_driver)->vadjustment; + gtk_adjustment_set_value + (adjustment, + adjustment->lower + idx * (adjustment->upper - adjustment->lower) / + GTK_CLIST (printer_driver)->rows); + + i = stpui_plist_get_command_type(pv); + if (i >= 0 && i < command_options_count) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(command_options[i].button), + TRUE); +} + +/* + * setup_open_callback() - + */ +static void +setup_open_callback (void) +{ + static gboolean first_time = TRUE; + manufacturer = stp_printer_get_manufacturer(stp_get_printer(pv->v)); + build_printer_driver_clist(); + + reset_preview (); + setup_update (); + +/* gtk_widget_set_sensitive(GTK_DIALOG(print_dialog)->action_area, FALSE); */ + gtk_widget_show (setup_dialog); + + if (first_time) + { + /* Make sure the driver scroller gets positioned correctly. */ + setup_update (); + first_time = FALSE; + } +} + +/* + * new_printer_open_callback() - + */ +static void +new_printer_open_callback (void) +{ + reset_preview (); + gtk_entry_set_text (GTK_ENTRY (new_printer_entry), ""); + gtk_widget_show (new_printer_dialog); +} + +static void +set_printer(void) +{ + manufacturer = stp_printer_get_manufacturer(tmp_printer); + build_printer_driver_clist(); + build_queue_combo(); + stp_set_driver (pv->v, stp_printer_get_driver (tmp_printer)); + stpui_plist_set_custom_command + (pv, gtk_entry_get_text (GTK_ENTRY (custom_command_entry))); + stpui_plist_set_output_filename + (pv, gtk_entry_get_text (GTK_ENTRY (file_entry))); + stp_set_file_parameter (pv->v, "PPDFile", + gtk_entry_get_text (GTK_ENTRY (ppd_file))); + gtk_label_set_text (GTK_LABEL (printer_model_label), + gettext (stp_printer_get_long_name (tmp_printer))); + + plist_callback (NULL, (gpointer) stpui_plist_current); +} + +/* + * setup_ok_callback() - + */ +static void +setup_ok_callback (void) +{ + gtk_widget_hide(ppd_browser); + gtk_widget_hide(file_browser); + gtk_widget_hide(setup_dialog); + set_printer(); + gtk_widget_set_sensitive(GTK_DIALOG(print_dialog)->action_area, TRUE); +} + +/* + * setup_cancel_callback() - + */ +static void +setup_cancel_callback (void) +{ + gtk_widget_hide(ppd_browser); + gtk_widget_hide(file_browser); + gtk_widget_hide(setup_dialog); + manufacturer = stp_printer_get_manufacturer(stp_get_printer(pv->v)); + build_printer_driver_clist(); + setup_update(); + gtk_widget_set_sensitive(GTK_DIALOG(print_dialog)->action_area, TRUE); +} + +/* + * setup_ok_callback() - + */ +static void +new_printer_ok_callback (void) +{ + const gchar *data = gtk_entry_get_text (GTK_ENTRY (new_printer_entry)); + stpui_plist_t key; + + if (strlen(data)) + { + memset(&key, 0, sizeof(key)); + stpui_printer_initialize (&key); + stpui_plist_copy(&key, pv); + stpui_plist_set_name(&key, data); + + if (stpui_plist_add (&key, 1)) + { + stp_vars_destroy(key.v); + g_free(key.name); + stpui_plist_current = stpui_plist_count - 1; + set_current_printer(); + build_printer_combo (); + set_printer(); + } + } + + gtk_widget_hide (new_printer_dialog); +} + +static void +pop_ppd_box(void) +{ + const stp_vars_t *v = stp_printer_get_defaults(tmp_printer); + if (stp_parameter_find_in_settings(v, "PPDFile")) + { + gtk_widget_show (ppd_label); + gtk_widget_show (ppd_box); + } + else + { + gtk_widget_hide (ppd_label); + gtk_widget_hide (ppd_box); + } +} + +static void +build_printer_driver_clist(void) +{ + int i; + int current_idx = 0; + gtk_clist_clear(GTK_CLIST(printer_driver)); + for (i = 0; i < stp_printer_model_count (); i ++) + { + const stp_printer_t *the_printer = stp_get_printer_by_index (i); + + if (strcmp(manufacturer, stp_printer_get_manufacturer(the_printer)) == 0) + { + gchar *tmp=g_strdup(gettext(stp_printer_get_long_name(the_printer))); + /* + * FIXME Somehow if the raw printer comes before any of the + * "real" printers in the list of printers created in module.c, + * this code barfs on any of those printers added later. For + * example, try listing olympus_LTX_stpi_module_data after + * raw_LTX_stpi_module_data. + */ + + gtk_clist_insert (GTK_CLIST (printer_driver), current_idx, &tmp); + gtk_clist_set_row_data (GTK_CLIST (printer_driver), current_idx, + (gpointer) i); + g_free(tmp); + current_idx++; + } + } +} + +static void +manufacturer_callback(GtkWidget *widget, /* I - Driver list */ + gint row, + gint column, + GdkEventButton *event, + gpointer data) +{ + static int calling_manufacturer_callback = 0; + gchar *text; + if (calling_manufacturer_callback) + return; + calling_manufacturer_callback++; + if (gtk_clist_get_text(GTK_CLIST(widget), row, column, &text)) + manufacturer = text; + build_printer_driver_clist(); + setup_update(); + calling_manufacturer_callback--; +} + +/* + * print_driver_callback() - Update the current printer driver. + */ +static void +print_driver_callback (GtkWidget *widget, /* I - Driver list */ + gint row, + gint column, + GdkEventButton *event, + gpointer data) /* I - Data */ +{ + char *tmp; + static int calling_print_driver_callback = 0; + if (calling_print_driver_callback) + return; + calling_print_driver_callback++; + invalidate_frame (); + invalidate_preview_thumbnail (); + reset_preview (); + data = gtk_clist_get_row_data (GTK_CLIST (widget), row); + tmp_printer = stp_get_printer_by_index ((gint) data); + tmp = stpui_build_standard_print_command(pv, tmp_printer); + gtk_entry_set_text(GTK_ENTRY(standard_cmd_entry), tmp); + g_free(tmp); + + pop_ppd_box(); + calling_print_driver_callback--; +} + +/* + * ppd_browse_callback() - + */ +static void +ppd_browse_callback (void) +{ + reset_preview (); + gtk_file_selection_set_filename (GTK_FILE_SELECTION (ppd_browser), + gtk_entry_get_text (GTK_ENTRY (ppd_file))); + gtk_widget_show (ppd_browser); +} + +/* + * ppd_ok_callback() - + */ +static void +ppd_ok_callback (void) +{ + reset_preview (); + gtk_widget_hide (ppd_browser); + gtk_entry_set_text + (GTK_ENTRY (ppd_file), + gtk_file_selection_get_filename (GTK_FILE_SELECTION (ppd_browser))); +} + +/* + * ppd_browse_callback() - + */ +static void +file_browse_callback (void) +{ + reset_preview (); + gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_browser), + gtk_entry_get_text (GTK_ENTRY (file_entry))); + gtk_widget_show (file_browser); +} + +/* + * file_ok_callback() - print to file and go away + */ +static void +file_ok_callback (void) +{ + const char *filename = + gtk_file_selection_get_filename(GTK_FILE_SELECTION(file_browser)); + gtk_widget_hide (file_browser); + gtk_entry_set_text(GTK_ENTRY(file_entry), filename); + stpui_plist_set_output_filename(pv, filename); + if (exit_after_file_ok) + { + runme = TRUE; + destroy_dialogs (); + } +} + +/* + * file_cancel_callback() - + */ +static void +file_cancel_callback (void) +{ + exit_after_file_ok = 0; + gtk_widget_hide (file_browser); + dialogs_set_sensitive (TRUE); +} + +static void +fill_buffer_writefunc(void *priv, const char *buffer, size_t bytes) +{ + int mask = 0; + int i; + int pixels = bytes / 4; + priv_t *p = (priv_t *) priv; + unsigned char *where = p->base_addr + p->offset; + const unsigned char *xbuffer = (const unsigned char *)buffer; + + if (p->bpp == 1) + { + memcpy(where, buffer, bytes); + p->offset += bytes; + } + else + { + if (bytes + p->offset > p->limit) + bytes = p->limit - p->offset; + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cyan_button))) + mask |= 1; + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(magenta_button))) + mask |= 2; + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(yellow_button))) + mask |= 4; + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(black_button))) + mask |= 8; + + memset(where, 0xff, pixels * 3); + for (i = 0; i < pixels; i++) + { + if (mask & 8) + { + where[0] -= xbuffer[3]; + where[1] -= xbuffer[3]; + where[2] -= xbuffer[3]; + } + if (mask & 1) + { + if (where[0] < xbuffer[0]) + where[0] = 0; + else + where[0] -= xbuffer[0]; + } + if (mask & 2) + { + if (where[1] < xbuffer[1]) + where[1] = 0; + else + where[1] -= xbuffer[1]; + } + if (mask & 4) + { + if (where[2] < xbuffer[2]) + where[2] = 0; + else + where[2] -= xbuffer[2]; + } + where += 3; + xbuffer += 4; + } + p->offset += pixels * 3; + } +} + +/* + * update_adjusted_thumbnail() + */ + +static void +redraw_color_swatch (void) +{ + static GdkGC *gc = NULL; + static GdkColormap *cmap; + + if (adjusted_thumbnail_data && swatch && swatch->widget.window) + { + if (gc == NULL) + { + gc = gdk_gc_new (swatch->widget.window); + cmap = gtk_widget_get_colormap (GTK_WIDGET(swatch)); + } + + if (!print_mode_is_color(pv->v)) + gdk_draw_gray_image(swatch->widget.window, gc, 0, 0, + thumbnail_w, thumbnail_h, GDK_RGB_DITHER_NORMAL, + adjusted_thumbnail_data, thumbnail_w); + else + gdk_draw_rgb_image(swatch->widget.window, gc, 0, 0, + thumbnail_w, thumbnail_h, GDK_RGB_DITHER_NORMAL, + adjusted_thumbnail_data, 3 * thumbnail_w); + } +} + +static void +initialize_thumbnail(void) +{ + int i; + if (stpui_get_thumbnail_func()) + { + const guchar *internal_thumbnail_data; + /* + * Fetch a thumbnail of the image we're to print from the Gimp. + */ + + thumbnail_w = thumbnail_hintw; + thumbnail_h = thumbnail_hinth; + internal_thumbnail_data = + (stpui_get_thumbnail_func()) (stpui_get_thumbnail_data(), &thumbnail_w, + &thumbnail_h, &thumbnail_bpp, 0); + if (adjusted_thumbnail_data) + g_free(adjusted_thumbnail_data); + if (preview_thumbnail_data) + g_free(preview_thumbnail_data); + if (thumbnail_data) + g_free(thumbnail_data); + + if (internal_thumbnail_data) + { + /* + * thumbnail_w and thumbnail_h have now been adjusted to the actual + * thumbnail dimensions. Now initialize a color-adjusted version of + * the thumbnail. + */ + + adjusted_thumbnail_data = g_malloc (3 * thumbnail_w * thumbnail_h); + preview_thumbnail_data = g_malloc (3 * thumbnail_w * thumbnail_h); + thumbnail_data = g_malloc (3 * thumbnail_w * thumbnail_h); + + switch (thumbnail_bpp) + { + case 1: + for (i = 0; i < thumbnail_w * thumbnail_h; i++) + { + gint val = internal_thumbnail_data[i]; + thumbnail_data[(3 * i) + 0] = val; + thumbnail_data[(3 * i) + 1] = val; + thumbnail_data[(3 * i) + 2] = val; + } + break; + case 3: + memcpy(thumbnail_data, internal_thumbnail_data, + 3 * thumbnail_w * thumbnail_h); + break; + case 2: + for (i = 0; i < thumbnail_w * thumbnail_h; i++) + { + gint val = internal_thumbnail_data[2 * i]; + gint alpha = internal_thumbnail_data[(2 * i) + 1]; + thumbnail_data[(3 * i) +0] = val * alpha / 255 + 255 - alpha; + thumbnail_data[(3 * i) +1] = val * alpha / 255 + 255 - alpha; + thumbnail_data[(3 * i) +2] = val * alpha / 255 + 255 - alpha; + } + break; + case 4: + for (i = 0; i < thumbnail_w * thumbnail_h; i++) + { + gint r = internal_thumbnail_data[(4 * i)]; + gint g = internal_thumbnail_data[(4 * i) + 1]; + gint b = internal_thumbnail_data[(4 * i) + 2]; + gint alpha = internal_thumbnail_data[(4 * i) + 3]; + thumbnail_data[(3 * i) + 0] = r * alpha / 255 + 255 - alpha; + thumbnail_data[(3 * i) + 1] = g * alpha / 255 + 255 - alpha; + thumbnail_data[(3 * i) + 2] = b * alpha / 255 + 255 - alpha; + } + break; + default: + break; + /* Whatever */ + } + thumbnail_bpp = 3; + } + else + { + thumbnail_h = 0; + thumbnail_w = 0; + } + } + else + { + thumbnail_h = 0; + thumbnail_w = 0; + } +} + +static int +compute_thumbnail(const stp_vars_t *v) +{ + priv_t priv; + int answer = 1; + stp_image_t *im = stpui_image_thumbnail_new(thumbnail_data, thumbnail_w, + thumbnail_h, thumbnail_bpp); + stp_vars_t *nv = stp_vars_create_copy(v); + stp_set_driver(nv, "raw-data-8"); + stp_set_top(nv, 0); + stp_set_left(nv, 0); + stp_set_width(nv, thumbnail_w); + stp_set_height(nv, thumbnail_h); + stp_set_outfunc(nv, fill_buffer_writefunc); + stp_set_outdata(nv, &priv); + stp_set_errfunc(nv, stpui_get_errfunc()); + stp_set_errdata(nv, stpui_get_errdata()); + if (!print_mode_is_color(nv)) + { + priv.bpp = 1; + stp_set_string_parameter(nv, "InkType", "RGBGray"); + } + else + { + priv.bpp = 4; + stp_set_string_parameter(nv, "InkType", "CMYK"); + } + stp_set_page_height(nv, thumbnail_h); + stp_set_page_width(nv, thumbnail_w); + stp_set_float_parameter(nv, "Density", 1.0); + stp_set_float_parameter(nv, "InkLimit", 0); + stp_set_string_parameter(nv, "InputImageType", "RGB"); + + priv.base_addr = adjusted_thumbnail_data; + priv.offset = 0; + priv.limit = thumbnail_bpp * thumbnail_h * thumbnail_w; + + if (stp_verify(nv) != 1 || stp_print(nv, im) != 1) + { + answer = 0; + fprintf(stderr, "Could not print thumbnail!\n"); + } + stp_vars_destroy(nv); + return answer; +} + +static void +set_thumbnail_orientation(void) +{ + gint x, y; + gint preview_limit = (thumbnail_h * thumbnail_w) - 1; + gint bpp; + if (!print_mode_is_color(pv->v)) + bpp = 1; + else + bpp = 3; + switch (physical_orientation) + { + case ORIENT_PORTRAIT: + memcpy(preview_thumbnail_data, adjusted_thumbnail_data, + bpp * thumbnail_h * thumbnail_w); + break; + case ORIENT_SEASCAPE: + for (x = 0; x < thumbnail_w; x++) + for (y = 0; y < thumbnail_h; y++) + memcpy((preview_thumbnail_data + + bpp * (preview_limit - (x * thumbnail_h + y))), + (adjusted_thumbnail_data + + bpp * ((thumbnail_h - y - 1) * thumbnail_w + x)), bpp); + break; + + case ORIENT_UPSIDEDOWN: + for (x = 0; x < thumbnail_h * thumbnail_w; x++) + memcpy((preview_thumbnail_data + bpp * (preview_limit - x)), + adjusted_thumbnail_data + bpp * x, bpp); + break; + case ORIENT_LANDSCAPE: + for (x = 0; x < thumbnail_w; x++) + for (y = 0; y < thumbnail_h; y++) + memcpy((preview_thumbnail_data + bpp * (x * thumbnail_h + y)), + (adjusted_thumbnail_data + + bpp * ((thumbnail_h - y - 1) * thumbnail_w + x)), bpp); + break; + } +} + +static void +update_adjusted_thumbnail (void) +{ + if (thumbnail_data && adjusted_thumbnail_data && do_update_thumbnail && + suppress_preview_update == 0) + { + if (compute_thumbnail(pv->v)) + { + set_thumbnail_orientation(); + redraw_color_swatch (); + preview_update (); + } + } +} + +static void +draw_arrow (GdkWindow *w, + GdkGC *gc, + gint paper_left, + gint paper_top) +{ + gint u = preview_ppi/2; + gint ox = paper_left + preview_ppi * paper_width / INCH / 2; + gint oy = paper_top + preview_ppi * paper_height / INCH / 2; + + oy -= preview_ppi * paper_height / INCH / 4; + if (oy < paper_top + u) + oy = paper_top + u; + gdk_draw_line (w, gc, ox, oy - u, ox - u, oy); + gdk_draw_line (w, gc, ox, oy - u, ox + u, oy); + gdk_draw_line (w, gc, ox, oy - u, ox, oy + u); +} + +static void +create_valid_preview(guchar **preview_data) +{ + if (adjusted_thumbnail_data) + { + gint bpp = (print_mode_is_color(pv->v)) ? 3 : 1; + gint v_denominator = preview_h > 1 ? preview_h - 1 : 1; + gint v_numerator = (preview_thumbnail_h - 1) % v_denominator; + gint v_whole = (preview_thumbnail_h - 1) / v_denominator; + gint h_denominator = preview_w > 1 ? preview_w - 1 : 1; + gint h_numerator = (preview_thumbnail_w - 1) % h_denominator; + gint h_whole = (preview_thumbnail_w - 1) / h_denominator; + gint adjusted_preview_width = bpp * preview_w; + gint adjusted_thumbnail_width = bpp * preview_thumbnail_w; + gint v_cur = 0; + gint v_last = -1; + gint v_error = v_denominator / 2; + gint y; + gint i; + + if (*preview_data) + g_free (*preview_data); + *preview_data = g_malloc (bpp * preview_h * preview_w); + + for (y = 0; y < preview_h; y++) + { + guchar *outbuf = *preview_data + adjusted_preview_width * y; + + if (v_cur == v_last) + memcpy (outbuf, outbuf-adjusted_preview_width, + adjusted_preview_width); + else + { + guchar *inbuf = preview_thumbnail_data - bpp + + adjusted_thumbnail_width * v_cur; + + gint h_cur = 0; + gint h_last = -1; + gint h_error = h_denominator / 2; + gint x; + + v_last = v_cur; + for (x = 0; x < preview_w; x++) + { + if (h_cur == h_last) + { + for (i = 0; i < bpp; i++) + outbuf[i] = outbuf[i - bpp]; + } + else + { + inbuf += bpp * (h_cur - h_last); + h_last = h_cur; + for (i = 0; i < bpp; i++) + outbuf[i] = inbuf[i]; + } + outbuf += bpp; + h_cur += h_whole; + h_error += h_numerator; + if (h_error >= h_denominator) + { + h_error -= h_denominator; + h_cur++; + } + } + } + v_cur += v_whole; + v_error += v_numerator; + if (v_error >= v_denominator) + { + v_error -= v_denominator; + v_cur++; + } + } + preview_valid = TRUE; + } +} + +/* + * preview_update_callback() - + */ +static void +do_preview_thumbnail (void) +{ + static GdkGC *gc = NULL; + static GdkGC *gcinv = NULL; + static GdkGC *gcset = NULL; + static guchar *preview_data = NULL; + gint opx = preview_x; + gint opy = preview_y; + gint oph = preview_h; + gint opw = preview_w; + gint paper_display_left, paper_display_top; + gint printable_display_left, printable_display_top; + gint paper_display_width, paper_display_height; + gint printable_display_width, printable_display_height; + int l_bottom = stp_get_top(pv->v) + stp_get_height(pv->v); + int l_right = stp_get_left(pv->v) + stp_get_width(pv->v); + + preview_ppi = preview_size_horiz * FINCH / (gdouble) paper_width; + + if (preview_ppi > preview_size_vert * FINCH / (gdouble) paper_height) + preview_ppi = preview_size_vert * FINCH / (gdouble) paper_height; + if (preview_ppi > MAX_PREVIEW_PPI) + preview_ppi = MAX_PREVIEW_PPI; + + if (preview == NULL || preview->widget.window == NULL) + return; + /* + * Center the page on the preview + */ + paper_display_width = MAX(3, ROUNDUP(preview_ppi * paper_width, INCH)); + paper_display_height = MAX(3, ROUNDUP(preview_ppi * paper_height, INCH)); + + paper_display_left = (preview_size_horiz - paper_display_width) / 2; + paper_display_top = (preview_size_vert - paper_display_height) / 2; + + printable_display_width = + MAX(3, ROUNDUP(preview_ppi * printable_width, INCH)); + printable_display_height = + MAX(3, ROUNDUP(preview_ppi * printable_height, INCH)); + + printable_display_left = paper_display_left + preview_ppi * left / INCH; + printable_display_top = paper_display_top + preview_ppi * top / INCH ; + + preview_x = + 1 + paper_display_left + preview_ppi * stp_get_left (pv->v) / INCH; + preview_y = + 1 + paper_display_top + preview_ppi * stp_get_top (pv->v) / INCH; + + if (!preview_valid) + { + gint preview_r = 1 + paper_display_left + preview_ppi * l_right / INCH; + gint preview_b = 1 + paper_display_top + preview_ppi * l_bottom / INCH; + preview_w = preview_r - preview_x; + preview_h = preview_b - preview_y; + if (preview_w >= printable_display_width) + preview_w = printable_display_width - 1; + if (preview_h >= printable_display_height) + preview_h = printable_display_height - 1; + } + + if (preview_w + preview_x > printable_display_left + printable_display_width) + preview_x--; + if (preview_h + preview_y > printable_display_top + printable_display_height) + preview_y--; + + if (gc == NULL) + { + gc = gdk_gc_new (preview->widget.window); + gcinv = gdk_gc_new (preview->widget.window); + gdk_gc_set_function (gcinv, GDK_INVERT); + gcset = gdk_gc_new (preview->widget.window); + gdk_gc_set_function (gcset, GDK_SET); + } + + if (!preview_valid) + create_valid_preview(&preview_data); + + if (printable_display_left < paper_display_left) + printable_display_left = paper_display_left; + if (printable_display_top < paper_display_top) + printable_display_top = paper_display_top; + if (printable_display_left + printable_display_width > + paper_display_left + paper_display_width) + printable_display_width = + paper_display_width - (paper_display_left - printable_display_left); + if (printable_display_top + printable_display_height > + paper_display_top + paper_display_height) + printable_display_height = + paper_display_height - (paper_display_top - printable_display_top); + if (need_exposure) + { + if (!frame_valid) + { + gdk_window_clear (preview->widget.window); + frame_valid = TRUE; + } + /* draw paper frame */ + gdk_draw_rectangle (preview->widget.window, gc, 0, + paper_display_left, paper_display_top, + paper_display_width, paper_display_height); + + /* draw printable frame */ + gdk_draw_rectangle (preview->widget.window, gc, 0, + printable_display_left, printable_display_top, + printable_display_width, printable_display_height); + need_exposure = FALSE; + } + else if (!frame_valid) + { + gdk_window_clear (preview->widget.window); + /* draw paper frame */ + gdk_draw_rectangle (preview->widget.window, gc, 0, + paper_display_left, paper_display_top, + paper_display_width, paper_display_height); + + /* draw printable frame */ + gdk_draw_rectangle (preview->widget.window, gc, 0, + printable_display_left, printable_display_top, + printable_display_width, printable_display_height); + frame_valid = TRUE; + } + else + { + if (opx + opw <= preview_x || opy + oph <= preview_y || + preview_x + preview_w <= opx || preview_y + preview_h <= opy) + { + gdk_window_clear_area (preview->widget.window, opx, opy, opw, oph); + } + else + { + if (opx < preview_x) + gdk_window_clear_area (preview->widget.window, + opx, opy, preview_x - opx, oph); + if (opy < preview_y) + gdk_window_clear_area (preview->widget.window, + opx, opy, opw, preview_y - opy); + if (opx + opw > preview_x + preview_w) + gdk_window_clear_area (preview->widget.window, + preview_x + preview_w, opy, + (opx + opw) - (preview_x + preview_w), oph); + if (opy + oph > preview_y + preview_h) + gdk_window_clear_area (preview->widget.window, + opx, preview_y + preview_h, + opw, (opy + oph) - (preview_y + preview_h)); + } + } + + draw_arrow (preview->widget.window, gcset, paper_display_left, + paper_display_top); + + if (!preview_valid) + gdk_draw_rectangle (preview->widget.window, gc, 1, + preview_x, preview_y, preview_w, preview_h); + else if (!print_mode_is_color(pv->v)) + gdk_draw_gray_image (preview->widget.window, gc, + preview_x, preview_y, preview_w, preview_h, + GDK_RGB_DITHER_NORMAL, preview_data, preview_w); + else + gdk_draw_rgb_image (preview->widget.window, gc, + preview_x, preview_y, preview_w, preview_h, + GDK_RGB_DITHER_NORMAL, preview_data, 3 * preview_w); + + /* If we're printing full bleed, redisplay the paper frame */ + if (preview_x <= paper_display_left || opx <= paper_display_left || + preview_y <= paper_display_top || opy <= paper_display_top || + preview_x + preview_w >= paper_display_left + paper_display_width || + opx + opw >= paper_display_left + paper_display_width || + preview_y + preview_h >= paper_display_top + paper_display_height || + opy + oph >= paper_display_top + paper_display_height) + gdk_draw_rectangle (preview->widget.window, gc, 0, + paper_display_left, paper_display_top, + paper_display_width, paper_display_height); + + + /* draw orientation arrow pointing to top-of-paper */ + draw_arrow (preview->widget.window, gcinv, paper_display_left, + paper_display_top); + gdk_flush(); +} + +static gboolean +idle_preview_thumbnail(gpointer data) +{ + set_orientation(pv->orientation); + do_preview_thumbnail(); + thumbnail_update_pending = FALSE; + return FALSE; +} + +static void +preview_expose (void) +{ + need_exposure = TRUE; + preview_update (); +} + +static void +preview_update (void) +{ + gdouble max_ppi_scaling; /* Maximum PPI for current page size */ + gdouble min_ppi_scaling; /* Minimum PPI for current page size */ + + suppress_preview_update++; + stp_get_media_size(pv->v, &paper_width, &paper_height); + + stp_get_imageable_area(pv->v, &left, &right, &bottom, &top); + + printable_width = right - left; + printable_height = bottom - top; + + if (pv->scaling < 0) + { + gdouble twidth; + + compute_scaling_limits(&min_ppi_scaling, &max_ppi_scaling); + + if (pv->scaling < 0 && pv->scaling > -min_ppi_scaling) + pv->scaling = -min_ppi_scaling; + + twidth = (FINCH * (gdouble) image_width / -pv->scaling); + print_width = twidth + .5; + print_height = (twidth * (gdouble) image_height / image_width) + .5; + GTK_ADJUSTMENT (scaling_adjustment)->lower = min_ppi_scaling; + GTK_ADJUSTMENT (scaling_adjustment)->upper = max_ppi_scaling; + GTK_ADJUSTMENT (scaling_adjustment)->value = -pv->scaling; + + if (!suppress_scaling_adjustment) + { + suppress_preview_reset++; + gtk_adjustment_changed (GTK_ADJUSTMENT (scaling_adjustment)); + suppress_scaling_callback = TRUE; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scaling_ppi), TRUE); + suppress_scaling_callback = FALSE; + gtk_adjustment_value_changed (GTK_ADJUSTMENT (scaling_adjustment)); + suppress_preview_reset--; + } + } + else if (auto_paper_size) + { + gdouble twidth = printable_width * pv->scaling / 100; + + print_width = twidth + .5; + print_height = + (twidth * (gdouble) image_height / (gdouble) image_width) + .5; + } + else + { + /* we do pv->scaling % of height or width, whatever is less */ + /* this is relative to printable size */ + if (image_width * printable_height > printable_width * image_height) + /* if image_width/image_height > printable_width/printable_height */ + /* i.e. if image is wider relative to its height than the width + of the printable area relative to its height */ + { + gdouble twidth = printable_width * pv->scaling / 100; + + print_width = twidth + .5; + print_height = + (twidth * (gdouble) image_height / (gdouble) image_width) + .5; + } + else + { + gdouble theight = printable_height * pv->scaling /100; + + print_height = theight + .5; + print_width = + (theight * (gdouble) image_width / (gdouble) image_height) + .5; + } + } + + if (auto_paper_size) + set_media_size(stp_get_string_parameter(pv->v, "PageSize")); + + stp_set_width(pv->v, print_width); + stp_set_height(pv->v, print_height); + + if (pv->invalid_mask & INVALID_LEFT) + stp_set_left (pv->v, (paper_width - print_width) / 2); + + if (stp_get_left(pv->v) < left) + stp_set_left(pv->v, left); + + if (stp_get_left (pv->v) > right - print_width) + stp_set_left (pv->v, right - print_width); + + if (pv->invalid_mask & INVALID_TOP) + stp_set_top (pv->v, ((paper_height - print_height) / 2)); + if (stp_get_top(pv->v) < top) + stp_set_top(pv->v, top); + + if (stp_get_top (pv->v) > bottom - print_height) + stp_set_top (pv->v, bottom - print_height); + + pv->invalid_mask = 0; + + set_all_entry_values(); + suppress_preview_update--; + + /* draw image */ + if (! suppress_preview_update && !thumbnail_update_pending) + { + thumbnail_update_pending = TRUE; + g_idle_add(idle_preview_thumbnail, NULL); + } +} + +/* + * preview_button_callback() - + */ +static void +preview_button_callback (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + if (event->type == GDK_BUTTON_PRESS) + { + if (preview_active == 0) + { + mouse_x = event->x; + mouse_y = event->y; + orig_left = stp_get_left (pv->v); + orig_top = stp_get_top (pv->v); + mouse_button = event->button; + buttons_mask = 1 << event->button; + buttons_pressed++; + preview_active = 1; + stpui_disable_help(); + move_constraint = + (event->state & GDK_SHIFT_MASK) ? MOVE_CONSTRAIN : MOVE_ANY; + if (event->state & GDK_CONTROL_MASK) + move_constraint |= MOVE_GRID; + } + else if ((buttons_mask & (1 << event->button)) == 0) + { + if (preview_active == 1) + { + stpui_enable_help(); + preview_active = -1; + stp_set_left (pv->v, orig_left); + stp_set_top (pv->v, orig_top); + preview_update (); + } + buttons_mask |= 1 << event->button; + buttons_pressed++; + } + } + else if (event->type == GDK_BUTTON_RELEASE) + { + buttons_pressed--; + buttons_mask &= ~(1 << event->button); + if (buttons_pressed == 0) + { + stpui_enable_help (); + preview_active = 0; + } + } +} + +/* + * preview_motion_callback() - + */ +static void +preview_motion_callback (GtkWidget *widget, + GdkEventMotion *event, + gpointer data) +{ + + gint old_top = stp_get_top (pv->v); + gint old_left = stp_get_left (pv->v); + gint new_top = old_top; + gint new_left = old_left; + gint steps; + if (preview_active != 1 || event->type != GDK_MOTION_NOTIFY) + return; + if (move_constraint == MOVE_CONSTRAIN) + { + int dx = abs(event->x - mouse_x); + int dy = abs(event->y - mouse_y); + if (dx > dy && dx > 3) + move_constraint = MOVE_HORIZONTAL; + else if (dy > dx && dy > 3) + move_constraint = MOVE_VERTICAL; + else + return; + } + + switch (mouse_button) + { + case 1: + if (move_constraint & MOVE_VERTICAL) + new_top = orig_top + INCH * (event->y - mouse_y) / preview_ppi; + if (move_constraint & MOVE_HORIZONTAL) + new_left = orig_left + INCH * (event->x - mouse_x) / preview_ppi; + break; + case 3: + if (move_constraint & MOVE_VERTICAL) + new_top = orig_top + event->y - mouse_y; + if (move_constraint & MOVE_HORIZONTAL) + new_left = orig_left + event->x - mouse_x; + break; + case 2: + if (move_constraint & MOVE_HORIZONTAL) + { + gint increment_width = + ((move_constraint & MOVE_GRID) && pv->scaling > 0) ? + printable_width * pv->scaling / 100 : print_width; + gint x_threshold = MAX (1, (preview_ppi * increment_width) / INCH); + if (event->x > mouse_x) + steps = MIN((event->x - mouse_x) / x_threshold, + ((right - orig_left) / increment_width) - 1); + else + steps = -(MIN((mouse_x - event->x) / x_threshold, + (orig_left - left) / increment_width)); + new_left = orig_left + steps * increment_width; + } + if (move_constraint & MOVE_VERTICAL) + { + gint increment_height = + ((move_constraint & MOVE_GRID) && pv->scaling > 0) ? + printable_height * pv->scaling / 100 : print_height; + gint y_threshold = MAX (1, (preview_ppi * increment_height) / INCH); + if (event->y > mouse_y) + steps = MIN((event->y - mouse_y) / y_threshold, + ((bottom - orig_top) / increment_height) - 1); + else + steps = -(MIN((mouse_y - event->y) / y_threshold, + (orig_top - top) / increment_height)); + new_top = orig_top + steps * increment_height; + } + break; + } + + if (new_top < top) + new_top = top; + if (new_top > bottom - print_height) + new_top = bottom - print_height; + if (new_left < left) + new_left = left; + if (new_left > right - print_width) + new_left = right - print_width; + + if (new_top != old_top || new_left != old_left) + { + stp_set_top (pv->v, new_top); + stp_set_left (pv->v, new_left); + preview_update (); + } +} + +static void +color_update (GtkAdjustment *adjustment) +{ + int i; + for (i = 0; i < current_option_count; i++) + { + option_t *opt = &(current_options[i]); + if (opt->fast_desc->p_type == STP_PARAMETER_TYPE_DOUBLE && + opt->fast_desc->p_level <= MAXIMUM_PARAMETER_LEVEL && + opt->info.flt.adjustment && + adjustment == GTK_ADJUSTMENT(opt->info.flt.adjustment)) + { + invalidate_preview_thumbnail (); + if (stp_get_float_parameter(pv->v, opt->fast_desc->name) != + adjustment->value) + { + stp_set_float_parameter(pv->v, opt->fast_desc->name, + adjustment->value); + update_adjusted_thumbnail(); + } + } + } +} + +static void +dimension_update (GtkAdjustment *adjustment) +{ + int i; + gdouble unit_scaler = units[pv->unit].scale; + for (i = 0; i < current_option_count; i++) + { + option_t *opt = &(current_options[i]); + if (opt->fast_desc->p_type == STP_PARAMETER_TYPE_DIMENSION && + opt->fast_desc->p_level <= MAXIMUM_PARAMETER_LEVEL && + opt->info.flt.adjustment && + adjustment == GTK_ADJUSTMENT(opt->info.flt.adjustment)) + { + invalidate_preview_thumbnail (); + if (stp_get_dimension_parameter(pv->v, opt->fast_desc->name) != + adjustment->value * unit_scaler) + { + stp_set_dimension_parameter(pv->v, opt->fast_desc->name, + adjustment->value * unit_scaler); + update_adjusted_thumbnail(); + } + } + } +} + +static void +set_controls_active (GtkObject *checkbutton, gpointer xopt) +{ + option_t *opt = (option_t *) xopt; + stp_parameter_t desc; + gboolean setting = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton)); + if (setting && opt->fast_desc->p_level <= MAXIMUM_PARAMETER_LEVEL) + { + switch (opt->fast_desc->p_type) + { + case STP_PARAMETER_TYPE_DOUBLE: + set_adjustment_active(opt, TRUE, FALSE); + if (! stp_check_float_parameter(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE)) + { + stp_describe_parameter(pv->v, opt->fast_desc->name, &desc); + stp_set_float_parameter(pv->v, opt->fast_desc->name, + desc.deflt.dbl); + stp_parameter_description_destroy(&desc); + } + stp_set_float_parameter_active(pv->v, opt->fast_desc->name, + STP_PARAMETER_ACTIVE); + break; + case STP_PARAMETER_TYPE_DIMENSION: + set_adjustment_active(opt, TRUE, FALSE); + if (! stp_check_dimension_parameter(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE)) + { + stp_describe_parameter(pv->v, opt->fast_desc->name, &desc); + stp_set_dimension_parameter(pv->v, opt->fast_desc->name, + desc.deflt.dimension); + stp_parameter_description_destroy(&desc); + } + stp_set_dimension_parameter_active(pv->v, opt->fast_desc->name, + STP_PARAMETER_ACTIVE); + break; + case STP_PARAMETER_TYPE_CURVE: + set_curve_active(opt, TRUE, FALSE); + if (! stp_check_curve_parameter(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE)) + { + stp_describe_parameter(pv->v, opt->fast_desc->name, &desc); + stp_set_curve_parameter(pv->v, opt->fast_desc->name, + desc.deflt.curve); + stp_parameter_description_destroy(&desc); + } + stp_set_curve_parameter_active(pv->v, opt->fast_desc->name, + STP_PARAMETER_ACTIVE); + break; + case STP_PARAMETER_TYPE_STRING_LIST: + set_combo_active(opt, TRUE, FALSE); + if (! stp_check_string_parameter(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE)) + { + stp_describe_parameter(pv->v, opt->fast_desc->name, &desc); + stp_set_string_parameter(pv->v, opt->fast_desc->name, + desc.deflt.str); + stp_parameter_description_destroy(&desc); + } + stp_set_string_parameter_active(pv->v, opt->fast_desc->name, + STP_PARAMETER_ACTIVE); + break; + case STP_PARAMETER_TYPE_BOOLEAN: + set_bool_active(opt, TRUE, FALSE); + if (! stp_check_boolean_parameter(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE)) + { + stp_describe_parameter(pv->v, opt->fast_desc->name, &desc); + stp_set_boolean_parameter(pv->v, opt->fast_desc->name, + desc.deflt.boolean); + stp_parameter_description_destroy(&desc); + } + stp_set_boolean_parameter_active(pv->v, opt->fast_desc->name, + STP_PARAMETER_ACTIVE); + break; + default: + break; + } + } + else + { + switch (opt->fast_desc->p_type) + { + case STP_PARAMETER_TYPE_DOUBLE: + set_adjustment_active(opt, FALSE, FALSE); + stp_set_float_parameter_active(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE); + break; + case STP_PARAMETER_TYPE_DIMENSION: + set_adjustment_active(opt, FALSE, FALSE); + stp_set_dimension_parameter_active(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE); + break; + case STP_PARAMETER_TYPE_CURVE: + set_curve_active(opt, FALSE, FALSE); + stp_set_curve_parameter_active(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE); + break; + case STP_PARAMETER_TYPE_STRING_LIST: + set_combo_active(opt, FALSE, FALSE); + stp_set_string_parameter_active(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE); + break; + case STP_PARAMETER_TYPE_BOOLEAN: /* ??? */ + set_bool_active(opt, FALSE, FALSE); + stp_set_boolean_parameter_active(pv->v, opt->fast_desc->name, + STP_PARAMETER_INACTIVE); + break; + default: + break; + } + } + invalidate_preview_thumbnail(); + update_adjusted_thumbnail(); +} + +static void +set_color_defaults (void) +{ + int i; + for (i = 0; i < current_option_count; i++) + { + option_t *opt = &(current_options[i]); + if (opt->fast_desc->p_level <= MAXIMUM_PARAMETER_LEVEL && + opt->fast_desc->p_class == STP_PARAMETER_CLASS_OUTPUT && + opt->is_active && !opt->fast_desc->read_only) + { + stp_parameter_activity_t active; + gdouble unit_scaler; + switch (opt->fast_desc->p_type) + { + case STP_PARAMETER_TYPE_DOUBLE: + active = + stp_get_float_parameter_active(pv->v, opt->fast_desc->name); + stp_set_float_parameter(pv->v, opt->fast_desc->name, + opt->info.flt.deflt); + stp_set_float_parameter_active(pv->v, opt->fast_desc->name, + active); + break; + case STP_PARAMETER_TYPE_DIMENSION: + unit_scaler = units[pv->unit].scale; + active = + stp_get_dimension_parameter_active(pv->v, + opt->fast_desc->name); + stp_set_dimension_parameter(pv->v, opt->fast_desc->name, + opt->info.flt.deflt * unit_scaler); + stp_set_dimension_parameter_active(pv->v, opt->fast_desc->name, + active); + break; + case STP_PARAMETER_TYPE_BOOLEAN: + active = + stp_get_boolean_parameter_active(pv->v, opt->fast_desc->name); + stp_set_boolean_parameter(pv->v, opt->fast_desc->name, + opt->info.bool.deflt); + stp_set_boolean_parameter_active(pv->v, opt->fast_desc->name, + active); + break; + case STP_PARAMETER_TYPE_STRING_LIST: + active = + stp_get_string_parameter_active(pv->v, opt->fast_desc->name); + stp_set_string_parameter(pv->v, opt->fast_desc->name, + opt->info.list.default_val); + stp_set_string_parameter_active(pv->v, opt->fast_desc->name, + active); + break; + default: + break; + } + } + } + + do_color_updates (); +} + +gint +stpui_do_print_dialog(void) +{ + /* + * Get printrc options... + */ + stpui_printrc_load (); + + /* + * Print dialog window... + */ + create_main_window(); + + gtk_main (); + gdk_flush (); + + /* + * Set printrc options... + */ + if (saveme) + stpui_printrc_save (); + + /* + * Return ok/cancel... + */ + return (runme); +} |