1/*
2 * "$Id: panel.c,v 1.19 2010/07/10 18:32:35 rlk Exp $"
3 *
4 *   Main window code for Print plug-in for the GIMP.
5 *
6 *   Copyright 1997-2003 Michael Sweet (mike@easysw.com),
7 *	Robert Krawitz (rlk@alum.mit.edu), Steve Miller (smiller@rni.net)
8 *      and Michael Natterer (mitch@gimp.org)
9 *
10 *   This program is free software; you can redistribute it and/or modify it
11 *   under the terms of the GNU General Public License as published by the Free
12 *   Software Foundation; either version 2 of the License, or (at your option)
13 *   any later version.
14 *
15 *   This program is distributed in the hope that it will be useful, but
16 *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18 *   for more details.
19 *
20 *   You should have received a copy of the GNU General Public License
21 *   along with this program; if not, write to the Free Software
22 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25#ifdef HAVE_CONFIG_H
26#include <config.h>
27#endif
28
29#define MAX_PREVIEW_PPI        (400)
30#define INCH 72
31#define FINCH ((gdouble) INCH)
32#define ROUNDUP(x, y) (((x) + ((y) - 1)) / (y))
33#define SCALE(x, y) (((x) + (1.0 / (2.0 * (y)))) * (y))
34
35#include <gutenprint/gutenprint-intl-internal.h>
36#include <gutenprintui2/gutenprintui.h>
37#include "gutenprintui-internal.h"
38
39#include <string.h>
40#include <stdio.h>
41
42#define MAXIMUM_PARAMETER_LEVEL STP_PARAMETER_LEVEL_ADVANCED4
43
44/*
45 * Constants for GUI.
46 */
47static int preview_size_vert = 360;
48static int preview_size_horiz = 300;
49static gdouble minimum_image_percent = 5.0;
50static const int thumbnail_hintw = 128;
51static const int thumbnail_hinth = 128;
52
53#define MOVE_CONSTRAIN	   0
54#define MOVE_HORIZONTAL	   1
55#define MOVE_VERTICAL      2
56#define MOVE_ANY           (MOVE_HORIZONTAL | MOVE_VERTICAL)
57#define MOVE_GRID	   4
58
59/*
60 *  Main window widgets
61 */
62
63static GtkWidget *main_vbox;
64static GtkWidget *main_hbox;
65static GtkWidget *right_vbox;
66static GtkWidget *notebook;
67
68static GtkWidget *output_color_vbox;
69static GtkWidget *cyan_button;
70static GtkWidget *magenta_button;
71static GtkWidget *yellow_button;
72static GtkWidget *black_button;
73static GtkWidget *red_button;
74static GtkWidget *green_button;
75static GtkWidget *blue_button;
76
77static GtkWidget *print_dialog;           /* Print dialog window */
78
79static GtkWidget *recenter_button;
80static GtkWidget *recenter_vertical_button;
81static GtkWidget *recenter_horizontal_button;
82
83static GtkWidget *left_entry;
84/*
85static GtkWidget *right_entry;
86*/
87static GtkWidget *right_border_entry;
88static GtkWidget *top_entry;
89/*
90static GtkWidget *bottom_entry;
91*/
92static GtkWidget *bottom_border_entry;
93static GtkWidget *width_entry;
94static GtkWidget *height_entry;
95static GtkWidget *units_hbox;
96static GtkWidget *units_label;
97
98static GtkWidget *custom_size_width;
99static GtkWidget *custom_size_height;
100static GtkWidget *show_all_paper_sizes_button;
101static GtkWidget *auto_paper_size_button;
102
103static GtkWidget *orientation_menu;    /* Orientation menu */
104
105static GtkWidget *scaling_percent;     /* Scale by percent */
106static GtkWidget *scaling_ppi;         /* Scale by pixels-per-inch */
107static GtkWidget *scaling_image;       /* Scale to the image */
108static GtkObject *scaling_adjustment;  /* Adjustment object for scaling */
109
110static GtkWidget *setup_dialog;        /* Setup dialog window */
111static GtkWidget *printer_driver;      /* Printer driver widget */
112static GtkWidget *printer_model_label; /* Printer model name */
113static GtkWidget *printer_crawler;     /* Scrolled Window for menu */
114static GtkWidget *printer_combo;       /* Combo for menu */
115static GtkWidget *manufacturer_clist;  /* Manufacturer widget */
116static GtkWidget *manufacturer_crawler;     /* Scrolled Window for menu */
117static gint plist_callback_id = -1;
118static GtkWidget *ppd_file;            /* PPD file entry */
119static GtkWidget *ppd_box;
120static GtkWidget *ppd_label;           /* PPD file entry */
121static GtkWidget *ppd_button;          /* PPD file browse button */
122static GtkWidget *ppd_browser;         /* File selection dialog for PPDs */
123static GtkWidget *ppd_model_label;     /* PPD file entry */
124static GtkWidget *ppd_model;           /* PPD file entry */
125static GtkWidget *new_printer_dialog;  /* New printer dialog window */
126static GtkWidget *new_printer_entry;   /* New printer text entry */
127static GtkWidget *file_button;         /* PPD file browse button */
128static GtkWidget *file_entry;          /* FSD for print files */
129static GtkWidget *file_browser;        /* FSD for print files */
130static GtkWidget *standard_cmd_entry;  /* FSD for print files */
131static GtkWidget *custom_command_entry;   /* FSD for print files */
132static GtkWidget *queue_combo;   /* FSD for print files */
133static gint queue_callback_id = -1;
134
135static GtkWidget *adjust_color_button;
136static GtkWidget *about_dialog;
137
138static GtkWidget *page_size_table;
139static GtkWidget *printer_features_table;
140static GtkWidget *color_adjustment_table;
141
142static GtkWidget *copy_count_spin_button;
143
144static gboolean preview_valid = FALSE;
145static gboolean frame_valid = FALSE;
146static gboolean need_exposure = FALSE;
147static gboolean suppress_scaling_adjustment = FALSE;
148static gboolean suppress_scaling_callback   = FALSE;
149static gboolean thumbnail_update_pending    = FALSE;
150static gboolean thumbnail_needs_rebuild     = FALSE;
151/*
152 * These are semaphores, not true booleans.
153 */
154static gint suppress_preview_update = 0;
155static gint suppress_preview_reset = 0;
156
157static GtkDrawingArea *preview = NULL;	/* Preview drawing area widget */
158static GtkDrawingArea *swatch = NULL;
159static gint mouse_x, mouse_y;		/* Last mouse position */
160static gint orig_top, orig_left;	/* Original mouse position at start */
161static gint buttons_pressed = 0;
162static gint preview_active = 0;
163static gint buttons_mask = 0;
164static gint move_constraint = 0;
165static gint mouse_button = -1;	/* Button being dragged with */
166static gint preview_thumbnail_w, preview_thumbnail_h;
167static gint preview_x, preview_y, preview_w, preview_h;
168
169static gint physical_orientation = -2; /* Actual orientation */
170
171static gint paper_width, paper_height; /* Physical width */
172static gint printable_width, printable_height;	/* Size of printable area */
173static gint print_width, print_height; /* Printed area of image */
174static gint left, right, top, bottom; /* Imageable region */
175static gint image_width, image_height; /* Image size (possibly rotated) */
176static gint image_true_width, image_true_height; /* Original image */
177static gdouble image_xres, image_yres; /* Original image resolution */
178static gint do_update_thumbnail = 0;
179static gint saveme = 0;		/* True if printrc should be saved */
180static gint runme = 0;		/* True if print should proceed */
181static gint exit_after_file_ok = 0; /* True if we should exit after file browser complete */
182static gint auto_paper_size = 0; /* True if we're using auto paper size now */
183
184
185
186static void scaling_update        (GtkAdjustment *adjustment);
187static void scaling_callback      (GtkWidget *widget);
188static void plist_callback        (GtkWidget *widget, gpointer data);
189static void queue_callback        (GtkWidget *widget, gpointer data);
190static void custom_media_size_callback(GtkWidget *widget, gpointer data);
191static void show_all_paper_sizes_callback(GtkWidget *widget, gpointer data);
192static void auto_paper_size_callback(GtkWidget *widget, gpointer data);
193static void combo_callback        (GtkWidget *widget, gpointer data);
194static void output_type_callback  (GtkWidget *widget, gpointer data);
195static void unit_callback         (GtkWidget *widget, gpointer data);
196static void orientation_callback  (GtkWidget *widget, gpointer data);
197static void ppd_file_callback     (GtkWidget *widget, gpointer data);
198static void printandsave_callback (void);
199static void about_callback        (void);
200static void print_callback        (void);
201static void save_callback         (void);
202static void setup_callback      (GtkWidget *widget);
203
204static void setup_update          (void);
205static void setup_open_callback   (void);
206static void setup_ok_callback     (void);
207static void setup_cancel_callback (void);
208static void new_printer_open_callback   (void);
209static void new_printer_ok_callback     (void);
210static void ppd_browse_callback   (void);
211static void ppd_ok_callback       (void);
212static void file_browse_callback   (void);
213static void file_ok_callback      (void);
214static void file_cancel_callback  (void);
215static void build_printer_driver_clist(void);
216static void print_driver_callback (GtkWidget      *widget,
217				   gint            row,
218				   gint            column,
219				   GdkEventButton *event,
220				   gpointer        data);
221static void manufacturer_callback (GtkWidget      *widget,
222				   gint            row,
223				   gint            column,
224				   GdkEventButton *event,
225				   gpointer        data);
226static void command_type_callback  (GtkWidget *widget, gpointer data);
227
228static void do_preview_thumbnail (void);
229static void invalidate_preview_thumbnail (void);
230static void invalidate_frame (void);
231
232static GtkWidget *color_adjust_dialog;
233
234static void preview_update              (void);
235static void preview_expose              (void);
236static void preview_button_callback     (GtkWidget      *widget,
237					 GdkEventButton *bevent,
238					 gpointer        data);
239static void preview_motion_callback     (GtkWidget      *widget,
240					 GdkEventMotion *mevent,
241					 gpointer        data);
242static void position_callback           (GtkWidget      *widget);
243static void position_button_callback    (GtkWidget      *widget,
244					 gpointer        data);
245static void copy_count_callback         (GtkAdjustment  *widget,
246					 gpointer        data);
247static void plist_build_combo(GtkWidget *combo,
248			      GtkWidget *label,
249			      stp_string_list_t *items,
250			      int active,
251			      const gchar *cur_item,
252			      const gchar *def_value,
253			      GCallback callback,
254			      gint *callback_id,
255			      int (*check_func)(const char *string),
256			      gpointer data);
257static void initialize_thumbnail(void);
258static void reset_callback (GtkObject *widget, gpointer data);
259static void set_color_defaults (void);
260static void set_printer_defaults (void);
261static void redraw_color_swatch (void);
262static void color_update (GtkAdjustment *adjustment);
263static void dimension_update (GtkAdjustment *adjustment);
264static void integer_update (GtkAdjustment *adjustment);
265static void set_controls_active (GtkObject *checkbutton, gpointer optno);
266static void update_adjusted_thumbnail (gboolean regenerate_image);
267
268static void set_media_size(const gchar *new_media_size);
269static const stp_printer_t *tmp_printer = NULL;
270
271static option_t *current_options = NULL;
272static int current_option_count = 0;
273
274static unit_t units[] =
275  {
276    { N_("Inch"), N_("Set the base unit of measurement to inches"),
277      72.0, NULL, "%.2f" },
278    { N_("cm"), N_("Set the base unit of measurement to centimetres"),
279      72.0 / 2.54, NULL, "%.2f" },
280    { N_("Points"), N_("Set the base unit of measurement to points (1/72\")"),
281      1.0, NULL, "%.0f" },
282    { N_("mm"), N_("Set the base unit of measurement to millimetres"),
283      72.0 / 25.4, NULL, "%.1f" },
284    { N_("Pica"), N_("Set the base unit of measurement to picas (1/12\")"),
285      72.0 / 12.0, NULL, "%.1f" },
286  };
287static const gint unit_count = sizeof(units) / sizeof(unit_t);
288
289static radio_group_t output_types[] =
290  {
291    { N_("Color"), N_("Color output"), "Color", NULL },
292    { N_("Grayscale"),
293      N_("Print in shades of gray using black ink"), "BW", NULL }
294  };
295
296static const gint output_type_count = (sizeof(output_types) /
297				       sizeof(radio_group_t));
298
299/*
300 * The order of these entries must match the order in command_t in
301 * gutenprintui.h
302 */
303static radio_group_t command_options[] =
304  {
305    { N_("Standard Command"), N_("Use standard print command"), "Standard", NULL },
306    { N_("Custom Command"), N_("Use custom print command"), "Custom", NULL },
307    { N_("File"), N_("Print to a file"), "File", NULL }
308  };
309
310static const gint command_options_count = (sizeof(command_options) /
311					   sizeof(radio_group_t));
312
313static gdouble preview_ppi = 10;
314
315static stp_string_list_t *printer_list = 0;
316static stpui_plist_t *pv;
317static const char *manufacturer = 0;
318
319static gint thumbnail_w, thumbnail_h, thumbnail_bpp;
320static guchar *thumbnail_data;
321static guchar *adjusted_thumbnail_data;
322static guchar *preview_thumbnail_data;
323
324static void
325set_stpui_curve_values(GtkWidget *gcurve, const stp_curve_t *seed)
326{
327  if (stp_curve_get_gamma(seed))
328    {
329      stpui_curve_set_gamma(STPUI_CURVE(gcurve), stp_curve_get_gamma(seed));
330    }
331  else
332    {
333      stp_curve_t *copy = stp_curve_create_copy(seed);
334      const float *fdata;
335      size_t count;
336      stp_curve_resample(copy, 256);
337      fdata = stp_curve_get_float_data(copy, &count);
338      stpui_curve_set_vector(STPUI_CURVE(gcurve), count, fdata);
339      stp_curve_destroy(copy);
340    }
341}
342
343static void
344set_stp_curve_values(GtkWidget *widget, option_t *opt)
345{
346  int i;
347  double lo, hi;
348  gfloat vector[256];
349  GtkWidget *gcurve = GTK_WIDGET(widget);
350  stp_curve_t *curve = stp_curve_create_copy(opt->info.curve.deflt);
351  stpui_curve_get_vector(STPUI_CURVE(gcurve), 256, vector);
352  stp_curve_get_bounds(opt->info.curve.deflt, &lo, &hi);
353  for (i = 0; i < 256; i++)
354    {
355      if (vector[i] > hi)
356	vector[i] = hi;
357      else if (vector[i] < lo)
358	vector[i] = lo;
359    }
360  switch (STPUI_CURVE(gcurve)->curve_type)
361    {
362    case STPUI_CURVE_TYPE_SPLINE:
363      stp_curve_set_interpolation_type(curve, STP_CURVE_TYPE_SPLINE);
364      break;
365    default:
366      stp_curve_set_interpolation_type(curve, STP_CURVE_TYPE_LINEAR);
367      break;
368    }
369  stp_curve_set_float_data(curve, 256, vector);
370  stp_set_curve_parameter(pv->v, opt->fast_desc->name, curve);
371  stp_curve_destroy(curve);
372}
373
374static int
375open_curve_editor(GtkObject *button, gpointer xopt)
376{
377  option_t *opt = (option_t *)xopt;
378  if (opt->info.curve.is_visible == FALSE)
379    {
380      GtkWidget *gcurve =
381	GTK_WIDGET(STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve);
382      const stp_curve_t *seed =
383	stp_get_curve_parameter(pv->v, opt->fast_desc->name);
384      stp_curve_t *nseed = NULL;
385      if (!seed)
386	seed = opt->info.curve.deflt;
387      if (seed)
388	nseed = stp_curve_create_copy(seed);
389      gtk_widget_set_sensitive(GTK_WIDGET(opt->checkbox), FALSE);
390      gtk_widget_show(GTK_WIDGET(opt->info.curve.dialog));
391      set_stpui_curve_values(gcurve, seed);
392      opt->info.curve.is_visible = TRUE;
393      if (opt->info.curve.current)
394	stp_curve_destroy(opt->info.curve.current);
395      opt->info.curve.current = nseed;
396      invalidate_preview_thumbnail();
397      update_adjusted_thumbnail(FALSE);
398    }
399/*  gtk_window_activate_focus(GTK_WINDOW(opt->info.curve.dialog)); */
400  return 1;
401}
402
403static int
404set_default_curve_callback(GtkObject *button, gpointer xopt)
405{
406  option_t *opt = (option_t *)xopt;
407  GtkWidget *gcurve =
408    GTK_WIDGET(STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve);
409  const stp_curve_t *seed = opt->info.curve.deflt;
410  set_stpui_curve_values(gcurve, seed);
411  set_stp_curve_values(gcurve, opt);
412  invalidate_preview_thumbnail();
413  update_adjusted_thumbnail(TRUE);
414  return 1;
415}
416
417static int
418set_previous_curve_callback(GtkObject *button, gpointer xopt)
419{
420  option_t *opt = (option_t *)xopt;
421  GtkWidget *gcurve =
422    GTK_WIDGET(STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve);
423  const stp_curve_t *seed = opt->info.curve.current;
424  if (!seed)
425    seed = opt->info.curve.deflt;
426  set_stpui_curve_values(gcurve, seed);
427  set_stp_curve_values(gcurve, opt);
428  invalidate_preview_thumbnail();
429  update_adjusted_thumbnail(TRUE);
430  return 1;
431}
432
433static int
434set_curve_callback(GtkObject *button, gpointer xopt)
435{
436  option_t *opt = (option_t *)xopt;
437  GtkWidget *gcurve =
438    GTK_WIDGET(STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve);
439  gtk_widget_hide(opt->info.curve.dialog);
440  gtk_widget_set_sensitive(GTK_WIDGET(opt->checkbox), TRUE);
441  opt->info.curve.is_visible = FALSE;
442  set_stp_curve_values(gcurve, opt);
443  if (opt->info.curve.current)
444    stp_curve_destroy(opt->info.curve.current);
445  opt->info.curve.current = NULL;
446  invalidate_preview_thumbnail();
447  update_adjusted_thumbnail(TRUE);
448  return 1;
449}
450
451static gint
452curve_draw_callback(GtkWidget *widget, GdkEvent *event, gpointer xopt)
453{
454  option_t *opt = (option_t *)xopt;
455  switch (event->type)
456    {
457    case GDK_BUTTON_RELEASE:
458      set_stp_curve_values(widget, opt);
459      invalidate_preview_thumbnail();
460      update_adjusted_thumbnail(TRUE);
461      break;
462    default:
463      break;
464    }
465  return 1;
466}
467
468static gint
469curve_type_changed(GtkWidget *widget, gpointer xopt)
470{
471  option_t *opt = (option_t *)xopt;
472  set_stp_curve_values(widget, opt);
473  invalidate_preview_thumbnail();
474  update_adjusted_thumbnail(TRUE);
475  return 1;
476}
477
478static int
479cancel_curve_callback(GtkObject *button, gpointer xopt)
480{
481  option_t *opt = (option_t *)xopt;
482  if (opt->info.curve.is_visible)
483    {
484      stp_set_curve_parameter(pv->v, opt->fast_desc->name,
485			      opt->info.curve.current);
486      stp_curve_destroy(opt->info.curve.current);
487      opt->info.curve.current = NULL;
488      gtk_widget_hide(opt->info.curve.dialog);
489      gtk_widget_set_sensitive(GTK_WIDGET(opt->checkbox), TRUE);
490      opt->info.curve.is_visible = FALSE;
491      invalidate_preview_thumbnail();
492      update_adjusted_thumbnail(TRUE);
493    }
494  return 1;
495}
496
497static void
498stpui_create_curve(option_t *opt,
499		   GtkTable *table,
500		   gint column,
501		   gint row,
502		   const gchar *text,
503		   const stp_curve_t *deflt,
504		   gboolean is_optional)
505{
506  double lower, upper;
507  opt->checkbox = gtk_check_button_new();
508  gtk_table_attach(GTK_TABLE(table), opt->checkbox,
509		   column, column + 1, row, row + 1,
510		   GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0);
511  if (is_optional)
512    gtk_widget_show(opt->checkbox);
513  else
514    gtk_widget_hide(opt->checkbox);
515
516  opt->info.curve.label = gtk_label_new(text);
517  gtk_misc_set_alignment (GTK_MISC (opt->info.curve.label), 0.0, 0.5);
518  gtk_table_attach (GTK_TABLE (table), opt->info.curve.label,
519                    column + 1, column + 2, row, row + 1,
520                    GTK_FILL, GTK_FILL, 0, 0);
521  gtk_widget_show (opt->info.curve.label);
522
523  opt->info.curve.button = gtk_button_new_with_label(_("Edit Curve..."));
524  g_signal_connect(G_OBJECT(opt->info.curve.button), "clicked",
525		   G_CALLBACK(open_curve_editor), opt);
526  gtk_table_attach (GTK_TABLE (table), opt->info.curve.button,
527                    column + 2, column + 3, row, row + 1,
528                    GTK_FILL, GTK_FILL, 0, 0);
529  gtk_widget_show(opt->info.curve.button);
530
531  opt->info.curve.dialog =
532    stpui_dialog_new(gettext(opt->fast_desc->text),
533		     GTK_WIN_POS_MOUSE, TRUE,
534		     _("Set Default"), set_default_curve_callback,
535		     opt, NULL, NULL, FALSE, FALSE,
536		     _("Restore Previous"), set_previous_curve_callback,
537		     opt, NULL, NULL, FALSE, FALSE,
538		     _("OK"), set_curve_callback,
539		     opt, NULL, NULL, FALSE, FALSE,
540		     _("Cancel"), cancel_curve_callback,
541		     opt, NULL, NULL, FALSE, FALSE,
542		     NULL);
543  opt->info.curve.gamma_curve = stpui_gamma_curve_new();
544  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(opt->info.curve.dialog)->vbox),
545		     opt->info.curve.gamma_curve, TRUE, TRUE, 0);
546  stp_curve_get_bounds(opt->info.curve.deflt, &lower, &upper);
547  stpui_curve_set_range
548    (STPUI_CURVE (STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve),
549     0.0, 1.0, lower, upper);
550  gtk_widget_set_usize
551    (GTK_WIDGET(STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve), 256, 256);
552  gtk_widget_show(opt->info.curve.gamma_curve);
553
554  g_signal_connect
555    (G_OBJECT(STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve),
556     "curve-type-changed", G_CALLBACK(curve_type_changed), opt);
557  g_signal_connect
558    (G_OBJECT(STPUI_GAMMA_CURVE(opt->info.curve.gamma_curve)->curve),
559     "event", G_CALLBACK(curve_draw_callback), opt);
560
561  if (opt->fast_desc->help)
562    {
563      stpui_set_help_data (opt->info.curve.label, opt->fast_desc->help);
564      stpui_set_help_data (opt->info.curve.button, opt->fast_desc->help);
565      stpui_set_help_data (opt->info.curve.gamma_curve, opt->fast_desc->help);
566    }
567}
568
569static int
570open_file_browser(GtkObject *button, gpointer xopt)
571{
572  option_t *opt = (option_t *)xopt;
573  GtkWidget *browser = opt->info.file.f_browser;
574  GtkWidget *entry = opt->info.file.f_entry;
575  gtk_file_selection_set_filename (GTK_FILE_SELECTION (browser),
576				   gtk_entry_get_text (GTK_ENTRY (entry)));
577  gtk_widget_show(opt->info.file.f_browser);
578  return 1;
579}
580
581static void
582file_entry_callback(GtkWidget *widget, gpointer xopt)
583{
584  const gchar *name = gtk_entry_get_text(GTK_ENTRY(widget));
585  if (name && pv && pv->v)
586    {
587      option_t *opt = (option_t *)xopt;
588      stp_set_file_parameter(pv->v, opt->fast_desc->name, name);
589    }
590}
591
592static int
593file_browser_ok_callback(GtkObject *browser_ok, gpointer xopt)
594{
595  option_t *opt = (option_t *)xopt;
596  GtkWidget *entry = opt->info.file.f_entry;
597  GtkWidget *browser = opt->info.file.f_browser;
598  gtk_widget_hide(opt->info.file.f_browser);
599  gtk_entry_set_text
600    (GTK_ENTRY (entry),
601     gtk_file_selection_get_filename (GTK_FILE_SELECTION (browser)));
602  file_entry_callback(entry, xopt);
603  return 1;
604}
605
606static void
607stpui_create_file_browser(option_t *opt,
608			  GtkTable *table,
609			  gint column,
610			  gint row,
611			  const gchar *text,
612			  gboolean is_optional)
613{
614  opt->checkbox = gtk_check_button_new();
615  gtk_table_attach(GTK_TABLE(table), opt->checkbox,
616		   column, column + 1, row, row + 1,
617		   GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0);
618  if (is_optional)
619    gtk_widget_show(opt->checkbox);
620  else
621    gtk_widget_hide(opt->checkbox);
622
623  opt->info.file.f_label = gtk_label_new(text);
624  gtk_misc_set_alignment (GTK_MISC (opt->info.file.f_label), 0.0, 0.5);
625  gtk_table_attach (GTK_TABLE (table), opt->info.file.f_label,
626                    column + 1, column + 2, row, row + 1,
627                    GTK_FILL, GTK_FILL, 0, 0);
628  gtk_widget_show (opt->info.file.f_label);
629
630  opt->info.file.f_entry = gtk_entry_new();
631  gtk_table_attach (GTK_TABLE (table), opt->info.file.f_entry,
632                    column + 2, column + 3, row, row + 1,
633                    GTK_FILL, GTK_FILL, 0, 0);
634  g_signal_connect(G_OBJECT(opt->info.file.f_entry), "activate",
635		   G_CALLBACK(file_entry_callback), opt);
636  if (stp_get_file_parameter(pv->v, opt->fast_desc->name))
637    gtk_entry_set_text
638      (GTK_ENTRY (opt->info.file.f_entry),
639       stp_get_file_parameter(pv->v, opt->fast_desc->name));
640  gtk_widget_show (opt->info.file.f_entry);
641
642  opt->info.file.f_button = gtk_button_new_with_label(_("Select File..."));
643  g_signal_connect(G_OBJECT(opt->info.file.f_button), "clicked",
644		   G_CALLBACK(open_file_browser), opt);
645  gtk_table_attach (GTK_TABLE (table), opt->info.file.f_button,
646                    column + 3, column + 4, row, row + 1,
647                    GTK_FILL, GTK_FILL, 0, 0);
648  gtk_widget_show(opt->info.file.f_button);
649
650  opt->info.file.f_browser =
651    gtk_file_selection_new(gettext(opt->fast_desc->text));
652
653  g_signal_connect
654    (G_OBJECT (GTK_FILE_SELECTION (opt->info.file.f_browser)->ok_button), "clicked",
655     G_CALLBACK (file_browser_ok_callback), opt);
656  g_signal_connect_object
657    (G_OBJECT (GTK_FILE_SELECTION (opt->info.file.f_browser)->cancel_button), "clicked",
658     G_CALLBACK (gtk_widget_hide), G_OBJECT (opt->info.file.f_browser), G_CONNECT_SWAPPED);
659
660  if (opt->fast_desc->help)
661    {
662      stpui_set_help_data (opt->info.file.f_label, opt->fast_desc->help);
663      stpui_set_help_data (opt->info.file.f_button, opt->fast_desc->help);
664      stpui_set_help_data (opt->info.file.f_entry, opt->fast_desc->help);
665      stpui_set_help_data (opt->info.file.f_browser, opt->fast_desc->help);
666    }
667}
668
669static int
670checkbox_callback(GtkObject *button, gpointer xopt)
671{
672  option_t *opt = (option_t *)xopt;
673  GtkWidget *checkbox = GTK_WIDGET(opt->info.bool.checkbox);
674  opt->info.bool.current =
675    gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox));
676  stp_set_boolean_parameter(pv->v, opt->fast_desc->name,
677			    opt->info.bool.current);
678  invalidate_frame();
679  invalidate_preview_thumbnail();
680  update_adjusted_thumbnail(TRUE);
681  preview_update();
682  return 1;
683}
684
685static int
686print_mode_is_color(const stp_vars_t *v)
687{
688  const char *printing_mode = stp_get_string_parameter(v, "PrintingMode");
689  if (!printing_mode)
690    {
691      int answer = 1;
692      stp_parameter_t desc;
693      stp_describe_parameter(v, "PrintingMode", &desc);
694      if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST &&
695	  strcmp(desc.deflt.str, "BW") == 0)
696	answer = 0;
697      stp_parameter_description_destroy(&desc);
698      return answer;
699    }
700  if (strcmp(printing_mode, "BW") == 0)
701    return 0;
702  else
703    return 1;
704}
705
706static void
707set_current_printer(void)
708{
709  pv = &(stpui_plist[stpui_plist_current]);
710  if (print_mode_is_color(pv->v))
711    stp_set_string_parameter(pv->v, "PrintingMode", "Color");
712  else
713    stp_set_string_parameter(pv->v, "PrintingMode", "BW");
714}
715
716
717static void
718stpui_create_boolean(option_t *opt,
719		     GtkTable *table,
720		     gint column,
721		     gint row,
722		     const gchar *text,
723		     int deflt,
724		     gboolean is_optional)
725{
726  opt->checkbox = gtk_check_button_new();
727  gtk_table_attach(GTK_TABLE(table), opt->checkbox,
728		   column, column + 1, row, row + 1,
729		   GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0);
730  if (is_optional)
731    gtk_widget_show(opt->checkbox);
732  else
733    gtk_widget_hide(opt->checkbox);
734
735  opt->info.bool.checkbox =
736    gtk_toggle_button_new_with_label(gettext(opt->fast_desc->text));
737  gtk_table_attach(GTK_TABLE(table), opt->info.bool.checkbox,
738		   column + 1, column + 3, row, row + 1,
739		   GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0);
740  gtk_widget_show(opt->info.bool.checkbox);
741  gtk_toggle_button_set_active
742    (GTK_TOGGLE_BUTTON(opt->info.bool.checkbox),
743     stp_get_boolean_parameter(pv->v, opt->fast_desc->name));
744  g_signal_connect(G_OBJECT(opt->info.bool.checkbox), "toggled",
745		   G_CALLBACK(checkbox_callback), opt);
746}
747
748static void
749build_queue_combo(void)
750{
751  plist_build_combo(queue_combo,
752		    NULL,
753		    stpui_system_print_queues,
754		    1,
755		    stpui_plist_get_queue_name(pv),
756		    NULL,
757		    G_CALLBACK(queue_callback),
758		    &queue_callback_id,
759		    NULL,
760		    NULL);
761}
762
763static void
764build_printer_combo(void)
765{
766  int i;
767  if (printer_list)
768    stp_string_list_destroy(printer_list);
769  printer_list = stp_string_list_create();
770  for (i = 0; i < stpui_plist_count; i++)
771    stp_string_list_add_string(printer_list,
772			       stpui_plist[i].name, stpui_plist[i].name);
773  plist_build_combo(printer_combo,
774		    NULL,
775		    printer_list,
776		    1,
777		    stp_string_list_param(printer_list, stpui_plist_current)->name,
778		    NULL,
779		    G_CALLBACK(plist_callback),
780		    &plist_callback_id,
781		    NULL,
782		    NULL);
783}
784
785static int
786check_page_size(const char *paper_size)
787{
788  const stp_papersize_t *ps = stp_get_papersize_by_name(paper_size);
789  if (ps && (ps->paper_unit == PAPERSIZE_ENGLISH_STANDARD ||
790	     ps->paper_unit == PAPERSIZE_METRIC_STANDARD))
791    return 1;
792  else
793    return 0;
794}
795
796static void
797build_page_size_combo(option_t *option)
798{
799  /*
800   * Some printers don't support any "standard" page sizes.  If the number
801   * of page sizes is small, just display all of them.
802   */
803  if (stpui_show_all_paper_sizes ||
804      stp_string_list_count(option->info.list.params) < 10)
805    plist_build_combo(option->info.list.combo, option->info.list.label,
806		      option->info.list.params, option->is_active,
807		      stp_get_string_parameter(pv->v, option->fast_desc->name),
808		      option->info.list.default_val,G_CALLBACK(combo_callback),
809		      &(option->info.list.callback_id), NULL, option);
810  else
811    plist_build_combo(option->info.list.combo, option->info.list.label,
812		      option->info.list.params, option->is_active,
813		      stp_get_string_parameter(pv->v, option->fast_desc->name),
814		      option->info.list.default_val,G_CALLBACK(combo_callback),
815		      &(option->info.list.callback_id),
816		      check_page_size, option);
817}
818
819static void
820build_a_combo(option_t *option)
821{
822  const gchar *new_value;
823  stp_parameter_activity_t active;
824  if (option->fast_desc &&
825      option->fast_desc->p_type == STP_PARAMETER_TYPE_STRING_LIST)
826    {
827      const gchar *val = stp_get_string_parameter(pv->v,
828						  option->fast_desc->name);
829      if (option->info.list.params == NULL || ! option->is_active ||
830	  stp_string_list_count(option->info.list.params) == 0)
831	stp_set_string_parameter(pv->v, option->fast_desc->name, NULL);
832      else if (!val || strlen(val) == 0 ||
833	       ! stp_string_list_is_present(option->info.list.params, val))
834	stp_set_string_parameter(pv->v, option->fast_desc->name,
835				 option->info.list.default_val);
836      if (strcmp(option->fast_desc->name, "PageSize") == 0)
837	build_page_size_combo(option);
838      else
839	plist_build_combo(option->info.list.combo, option->info.list.label,
840			  option->info.list.params,
841			  option->is_active,
842			  stp_get_string_parameter(pv->v,
843						   option->fast_desc->name),
844			  option->info.list.default_val, G_CALLBACK(combo_callback),
845			  &(option->info.list.callback_id), NULL, option);
846      if (strcmp(option->fast_desc->name, "PageSize") == 0)
847	set_media_size
848	  (stp_get_string_parameter(pv->v, option->fast_desc->name));
849    }
850  else
851    plist_build_combo(option->info.list.combo, option->info.list.label,
852		      NULL, 0, "", "", G_CALLBACK(combo_callback),
853		      &(option->info.list.callback_id), NULL, option);
854  new_value =
855    stpui_combo_get_name(option->info.list.combo, option->info.list.params);
856  active = stp_get_string_parameter_active(pv->v, option->fast_desc->name);
857  stp_set_string_parameter(pv->v, option->fast_desc->name, new_value);
858  stp_set_string_parameter_active(pv->v, option->fast_desc->name, active);
859}
860
861static void
862populate_options(const stp_vars_t *v)
863{
864  stp_parameter_list_t params = stp_get_parameter_list(v);
865  int i;
866  int idx;
867  if (current_options)
868    {
869      for (i = 0; i < current_option_count; i++)
870	{
871	  option_t *opt = &(current_options[i]);
872	  switch (opt->fast_desc->p_type)
873	    {
874	    case STP_PARAMETER_TYPE_STRING_LIST:
875	      if (opt->info.list.combo)
876		{
877		  gtk_widget_destroy(opt->info.list.combo);
878		  gtk_widget_destroy(opt->info.list.label);
879		  if (opt->info.list.params)
880		    stp_string_list_destroy(opt->info.list.params);
881		  g_free(opt->info.list.default_val);
882		}
883	      break;
884	    case STP_PARAMETER_TYPE_DOUBLE:
885	    case STP_PARAMETER_TYPE_DIMENSION:
886	    case STP_PARAMETER_TYPE_INT:
887	      if (opt->info.flt.adjustment)
888		{
889		  gtk_widget_destroy
890		    (GTK_WIDGET
891		     (SCALE_ENTRY_SCALE(opt->info.flt.adjustment)));
892		  gtk_widget_destroy
893		    (GTK_WIDGET
894		     (SCALE_ENTRY_LABEL(opt->info.flt.adjustment)));
895		  gtk_widget_destroy
896		    (GTK_WIDGET
897		     (SCALE_ENTRY_SPINBUTTON(opt->info.flt.adjustment)));
898		}
899	      break;
900	    case STP_PARAMETER_TYPE_CURVE:
901	      gtk_widget_destroy(GTK_WIDGET(opt->info.curve.label));
902	      gtk_widget_destroy(GTK_WIDGET(opt->info.curve.button));
903	      gtk_widget_destroy(GTK_WIDGET(opt->info.curve.dialog));
904	      if (opt->info.curve.current)
905		stp_curve_destroy(opt->info.curve.current);
906	      break;
907	    case STP_PARAMETER_TYPE_BOOLEAN:
908	      gtk_widget_destroy(GTK_WIDGET(opt->info.bool.checkbox));
909	      break;
910	    case STP_PARAMETER_TYPE_FILE:
911	      gtk_widget_destroy(GTK_WIDGET(opt->info.file.f_label));
912	      gtk_widget_destroy(GTK_WIDGET(opt->info.file.f_button));
913	      gtk_widget_destroy(GTK_WIDGET(opt->info.file.f_entry));
914	      gtk_widget_destroy(GTK_WIDGET(opt->info.file.f_browser));
915	      break;
916	    default:
917	      break;
918	    }
919	  if (opt->checkbox)
920	    gtk_widget_destroy(GTK_WIDGET(opt->checkbox));
921	  if (opt->reset_btn)
922	    gtk_widget_destroy(GTK_WIDGET(opt->reset_btn));
923	}
924      g_free(current_options);
925    }
926  current_option_count = stp_parameter_list_count(params);
927  current_options = g_malloc(sizeof(option_t) * current_option_count);
928
929  for (idx = 0, i = 0; i < current_option_count; i++)
930    {
931      stp_parameter_t desc;
932      const stp_parameter_t *param = stp_parameter_list_param(params, i);
933      if (!param->read_only &&
934	  (param->p_class == STP_PARAMETER_CLASS_OUTPUT ||
935	   param->p_class == STP_PARAMETER_CLASS_FEATURE ||
936	   (param->p_class == STP_PARAMETER_CLASS_CORE &&
937	    strcmp(param->name, "PageSize") == 0)))
938	{
939	  option_t *opt = &(current_options[idx]);
940	  opt->fast_desc = stp_parameter_list_param(params, i);
941	  stp_describe_parameter(v, opt->fast_desc->name, &desc);
942	  opt->checkbox = NULL;
943	  opt->reset_btn = NULL;
944	  opt->is_active = 0;
945	  opt->is_enabled = 0;
946	  switch (opt->fast_desc->p_type)
947	    {
948	    case STP_PARAMETER_TYPE_STRING_LIST:
949	      opt->info.list.callback_id = -1;
950	      opt->info.list.default_val = g_strdup(desc.deflt.str);
951	      if (desc.bounds.str)
952		opt->info.list.params =
953		  stp_string_list_create_copy(desc.bounds.str);
954	      else
955		opt->info.list.params = NULL;
956	      opt->info.list.combo = NULL;
957	      opt->info.list.label = NULL;
958	      opt->is_active = desc.is_active;
959	      break;
960	    case STP_PARAMETER_TYPE_DOUBLE:
961	      opt->info.flt.adjustment = NULL;
962	      opt->info.flt.upper = desc.bounds.dbl.upper;
963	      opt->info.flt.lower = desc.bounds.dbl.lower;
964	      opt->info.flt.deflt = desc.deflt.dbl;
965	      opt->info.flt.scale = 1.0;
966	      opt->is_active = desc.is_active;
967	      break;
968	    case STP_PARAMETER_TYPE_DIMENSION:
969	      opt->info.flt.adjustment = NULL;
970	      opt->info.flt.upper = desc.bounds.dimension.upper;
971	      opt->info.flt.lower = desc.bounds.dimension.lower;
972	      opt->info.flt.deflt = desc.deflt.dimension;
973	      opt->info.flt.scale = 1.0;
974	      opt->is_active = desc.is_active;
975	      break;
976	    case STP_PARAMETER_TYPE_INT:
977	      opt->info.flt.adjustment = NULL;
978	      opt->info.flt.upper = desc.bounds.integer.upper;
979	      opt->info.flt.lower = desc.bounds.integer.lower;
980	      opt->info.flt.deflt = desc.deflt.dimension;
981	      opt->info.flt.scale = 1.0;
982	      opt->is_active = desc.is_active;
983	      break;
984	    case STP_PARAMETER_TYPE_CURVE:
985	      opt->info.curve.label = NULL;
986	      opt->info.curve.button = NULL;
987	      opt->info.curve.dialog = NULL;
988	      opt->info.curve.gamma_curve = NULL;
989	      opt->info.curve.current = NULL;
990	      opt->info.curve.deflt = desc.deflt.curve;
991	      opt->info.curve.is_visible = FALSE;
992	      opt->is_active = desc.is_active;
993	      break;
994	    case STP_PARAMETER_TYPE_BOOLEAN:
995	      opt->info.bool.checkbox = NULL;
996	      opt->info.bool.current = 0;
997	      opt->info.bool.deflt = desc.deflt.boolean;
998	      opt->is_active = desc.is_active;
999	      break;
1000	    case STP_PARAMETER_TYPE_FILE:
1001	      opt->info.file.f_label = NULL;
1002	      opt->info.file.f_button = NULL;
1003	      opt->info.file.f_entry = NULL;
1004	      opt->info.file.f_browser = NULL;
1005	      opt->info.file.f_is_visible = FALSE;
1006	      opt->is_active = desc.is_active;
1007	      break;
1008	    default:
1009	      break;
1010	    }
1011	  idx++;
1012	  stp_parameter_description_destroy(&desc);
1013	}
1014    }
1015  current_option_count = idx;
1016  stp_parameter_list_destroy(params);
1017}
1018
1019static void
1020destroy_something(GtkWidget *widget, gpointer data)
1021{
1022  gtk_widget_destroy(widget);
1023}
1024
1025static void
1026add_reset_button(option_t *opt, GtkWidget *table, gint column, gint row)
1027{
1028  GtkWidget *button = gtk_button_new_with_label(_("Reset"));
1029  gtk_table_attach(GTK_TABLE(table), button, column, column + 1,
1030		   row, row + 1, GTK_FILL, GTK_FILL, 0, 0);
1031  g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(reset_callback), opt);
1032  opt->reset_btn = button;
1033  gtk_widget_show(button);
1034}
1035
1036static void
1037populate_option_table(GtkWidget *table, int p_class)
1038{
1039  int i, j;
1040  int current_pos = 0;
1041  GtkWidget *previous_sep = NULL;
1042  int counts[STP_PARAMETER_LEVEL_INVALID][STP_PARAMETER_TYPE_INVALID];
1043  int vpos[STP_PARAMETER_LEVEL_INVALID][STP_PARAMETER_TYPE_INVALID];
1044  for (i = 0; i < STP_PARAMETER_LEVEL_INVALID; i++)
1045    for (j = 0; j < STP_PARAMETER_TYPE_INVALID; j++)
1046      {
1047	vpos[i][j] = 0;
1048	counts[i][j] = 0;
1049      }
1050
1051
1052  gtk_container_foreach(GTK_CONTAINER(table), destroy_something, NULL);
1053
1054  /* First scan the options to figure out where to start */
1055  for (i = 0; i < current_option_count; i++)
1056    {
1057      const stp_parameter_t *desc = current_options[i].fast_desc;
1058      /*
1059       * Specialize the core parameters (page size is the only one we want)
1060       * Yuck.
1061       */
1062      if (!desc->read_only && desc->p_class == p_class &&
1063	  (desc->p_class != STP_PARAMETER_CLASS_CORE ||
1064	   strcmp(desc->name, "PageSize") == 0))
1065	{
1066	  switch (desc->p_type)
1067	    {
1068	    case STP_PARAMETER_TYPE_STRING_LIST:
1069	    case STP_PARAMETER_TYPE_DIMENSION:
1070	    case STP_PARAMETER_TYPE_INT:
1071	    case STP_PARAMETER_TYPE_DOUBLE:
1072	    case STP_PARAMETER_TYPE_CURVE:
1073	    case STP_PARAMETER_TYPE_BOOLEAN:
1074	    case STP_PARAMETER_TYPE_FILE:
1075	      counts[desc->p_level][desc->p_type]++;
1076	      break;
1077	    default:
1078	      break;
1079	    }
1080	}
1081    }
1082
1083  /* Now, figure out where we're going to put the options */
1084  for (i = 0; i <= MAXIMUM_PARAMETER_LEVEL + 1; i++)
1085    {
1086      int level_count = 0;
1087      if (i <= MAXIMUM_PARAMETER_LEVEL)
1088	for (j = 0; j < STP_PARAMETER_TYPE_INVALID; j++)
1089	  level_count += counts[i][j];
1090      if (level_count > 0 && current_pos > 0)
1091	{
1092	  GtkWidget *sep = gtk_hseparator_new();
1093	  gtk_table_attach (GTK_TABLE(table), sep, 0, 4,
1094			    current_pos, current_pos + 1,
1095			    GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0);
1096	  if (previous_sep)
1097	    gtk_widget_show(previous_sep);
1098	  previous_sep = sep;
1099	  current_pos++;
1100	}
1101      if (i <= MAXIMUM_PARAMETER_LEVEL)
1102	for (j = 0; j < STP_PARAMETER_TYPE_INVALID; j++)
1103	  {
1104	    vpos[i][j] = current_pos;
1105	    current_pos += counts[i][j];
1106	  }
1107    }
1108
1109  for (i = 0; i < current_option_count; i++)
1110    {
1111      option_t *opt = &(current_options[i]);
1112      const stp_curve_t *xcurve;
1113      const stp_parameter_t *desc = opt->fast_desc;
1114      if (!desc->read_only && desc->p_class == p_class &&
1115	  (desc->p_class != STP_PARAMETER_CLASS_CORE ||
1116	   strcmp(desc->name, "PageSize") == 0))
1117	{
1118	  gdouble unit_scaler;
1119	  gdouble minor_increment;
1120	  gint digits;
1121	  if (p_class == STP_PARAMETER_CLASS_OUTPUT)
1122	    opt->reset_all = FALSE;
1123	  else
1124	    opt->reset_all = TRUE;
1125	  switch (desc->p_type)
1126	    {
1127	    case STP_PARAMETER_TYPE_STRING_LIST:
1128	      add_reset_button(opt, table, 4, vpos[desc->p_level][desc->p_type]);
1129	      stpui_create_new_combo(opt, table, 0,
1130				     vpos[desc->p_level][desc->p_type]++,
1131				     !(desc->is_mandatory));
1132	      if (desc->p_level > MAXIMUM_PARAMETER_LEVEL)
1133		stp_set_string_parameter_active(pv->v, desc->name,
1134						STP_PARAMETER_INACTIVE);
1135	      break;
1136	    case STP_PARAMETER_TYPE_DOUBLE:
1137	      add_reset_button(opt, table, 4, vpos[desc->p_level][desc->p_type]);
1138	      stpui_create_scale_entry(opt, GTK_TABLE(table), 0,
1139				       vpos[desc->p_level][desc->p_type]++,
1140				       gettext(desc->text), 200, 0,
1141				       opt->info.flt.deflt,
1142				       opt->info.flt.lower,
1143				       opt->info.flt.upper,
1144				       .001, .01, 3, TRUE, 0, 0, NULL,
1145				       !(desc->is_mandatory));
1146	      stpui_set_adjustment_tooltip(opt->info.flt.adjustment,
1147					   gettext(desc->help));
1148	      g_signal_connect(G_OBJECT(opt->info.flt.adjustment),
1149			       "value_changed",
1150			       G_CALLBACK(color_update), opt);
1151	      if (desc->p_level > MAXIMUM_PARAMETER_LEVEL)
1152		stp_set_float_parameter_active(pv->v, desc->name,
1153					       STP_PARAMETER_INACTIVE);
1154	      break;
1155	    case STP_PARAMETER_TYPE_DIMENSION:
1156	      unit_scaler = units[pv->unit].scale;
1157	      if (unit_scaler > 100)
1158		{
1159		  digits = 3;
1160		  minor_increment = .001;
1161		}
1162	      else if (unit_scaler > 10)
1163		{
1164		  digits = 2;
1165		  minor_increment = .01;
1166		}
1167	      else if (unit_scaler > 1)
1168		{
1169		  digits = 1;
1170		  minor_increment = .1;
1171		}
1172	      else
1173		{
1174		  digits = 0;
1175		  minor_increment = 1;
1176		}
1177	      add_reset_button(opt, table, 4, vpos[desc->p_level][desc->p_type]);
1178	      stpui_create_scale_entry(opt, GTK_TABLE(table), 0,
1179				       vpos[desc->p_level][desc->p_type]++,
1180				       gettext(desc->text), 200, 0,
1181				       opt->info.flt.deflt / unit_scaler,
1182				       opt->info.flt.lower / unit_scaler,
1183				       opt->info.flt.upper / unit_scaler,
1184				       minor_increment, minor_increment * 10,
1185				       digits, TRUE, 0, 0, NULL,
1186				       !(desc->is_mandatory));
1187	      stpui_set_adjustment_tooltip(opt->info.flt.adjustment,
1188					   gettext(desc->help));
1189	      g_signal_connect(G_OBJECT(opt->info.flt.adjustment),
1190			       "value_changed",
1191			       G_CALLBACK(dimension_update), opt);
1192	      if (desc->p_level > MAXIMUM_PARAMETER_LEVEL)
1193		stp_set_dimension_parameter_active(pv->v, desc->name,
1194						   STP_PARAMETER_INACTIVE);
1195	      break;
1196	    case STP_PARAMETER_TYPE_INT:
1197	      add_reset_button(opt, table, 4, vpos[desc->p_level][desc->p_type]);
1198	      stpui_create_scale_entry(opt, GTK_TABLE(table), 0,
1199				       vpos[desc->p_level][desc->p_type]++,
1200				       gettext(desc->text), 200, 0,
1201				       opt->info.flt.deflt,
1202				       opt->info.flt.lower,
1203				       opt->info.flt.upper,
1204				       1, 10, 0, TRUE, 0, 0, NULL,
1205				       !(desc->is_mandatory));
1206	      stpui_set_adjustment_tooltip(opt->info.flt.adjustment,
1207					   gettext(desc->help));
1208	      g_signal_connect(G_OBJECT(opt->info.flt.adjustment),
1209			       "value_changed",
1210			       G_CALLBACK(integer_update), opt);
1211	      if (desc->p_level > MAXIMUM_PARAMETER_LEVEL)
1212		stp_set_int_parameter_active(pv->v, desc->name,
1213					     STP_PARAMETER_INACTIVE);
1214	      break;
1215	    case STP_PARAMETER_TYPE_CURVE:
1216	      xcurve = stp_get_curve_parameter(pv->v, opt->fast_desc->name);
1217	      if (xcurve)
1218		opt->info.curve.current = stp_curve_create_copy(xcurve);
1219	      else
1220		opt->info.curve.current = NULL;
1221	      add_reset_button(opt, table, 4, vpos[desc->p_level][desc->p_type]);
1222	      stpui_create_curve(opt, GTK_TABLE(table), 0,
1223				 vpos[desc->p_level][desc->p_type]++,
1224				 gettext(desc->text), opt->info.curve.deflt,
1225				 !(desc->is_mandatory));
1226	      if (desc->p_level > MAXIMUM_PARAMETER_LEVEL)
1227		stp_set_curve_parameter_active(pv->v, desc->name,
1228					       STP_PARAMETER_INACTIVE);
1229	      break;
1230	    case STP_PARAMETER_TYPE_BOOLEAN:
1231	      opt->info.bool.current =
1232		stp_get_boolean_parameter(pv->v, opt->fast_desc->name);
1233	      add_reset_button(opt, table, 4, vpos[desc->p_level][desc->p_type]);
1234	      stpui_create_boolean(opt, GTK_TABLE(table), 0,
1235				   vpos[desc->p_level][desc->p_type]++,
1236				   gettext(desc->text), opt->info.bool.deflt,
1237				   !(desc->is_mandatory));
1238	      if (desc->p_level > MAXIMUM_PARAMETER_LEVEL)
1239		stp_set_boolean_parameter_active(pv->v, desc->name,
1240						 STP_PARAMETER_INACTIVE);
1241	      break;
1242	    case STP_PARAMETER_TYPE_RAW:
1243	      stp_set_raw_parameter_active(pv->v, opt->fast_desc->name,
1244					   STP_PARAMETER_INACTIVE);
1245	      break;
1246	    case STP_PARAMETER_TYPE_FILE:
1247	      if (strcmp(opt->fast_desc->name, "PPDFile") != 0)
1248		{
1249		  add_reset_button(opt, table, 4, vpos[desc->p_level][desc->p_type]);
1250		  stpui_create_file_browser(opt, GTK_TABLE(table), 0,
1251					    vpos[desc->p_level][desc->p_type]++,
1252					    gettext(desc->text),
1253					    !(desc->is_mandatory));
1254		}
1255	      if (desc->p_level > MAXIMUM_PARAMETER_LEVEL)
1256		stp_set_file_parameter_active(pv->v, desc->name,
1257					      STP_PARAMETER_INACTIVE);
1258	      break;
1259	    default:
1260	      break;
1261	    }
1262	  if (opt->checkbox)
1263	    g_signal_connect
1264	      (G_OBJECT(opt->checkbox), "toggled",
1265	       G_CALLBACK(set_controls_active), opt);
1266	}
1267    }
1268}
1269
1270static void
1271set_options_active(const char *omit)
1272{
1273  int i;
1274  for (i = 0; i < current_option_count; i++)
1275    {
1276      option_t *opt = &(current_options[i]);
1277      const stp_parameter_t *desc = opt->fast_desc;
1278      GtkObject *adj;
1279      if (omit && strcmp(omit, opt->fast_desc->name) == 0)
1280	continue;
1281      switch (desc->p_type)
1282	{
1283	case STP_PARAMETER_TYPE_STRING_LIST:
1284	  build_a_combo(opt);
1285	  break;
1286	case STP_PARAMETER_TYPE_DOUBLE:
1287	case STP_PARAMETER_TYPE_DIMENSION:
1288	case STP_PARAMETER_TYPE_INT:
1289	  adj = opt->info.flt.adjustment;
1290	  if (adj)
1291	    {
1292	      if (opt->is_active && desc->p_level <= MAXIMUM_PARAMETER_LEVEL)
1293		{
1294		  gtk_widget_show(GTK_WIDGET(SCALE_ENTRY_LABEL(adj)));
1295		  gtk_widget_show(GTK_WIDGET(SCALE_ENTRY_SCALE(adj)));
1296		  gtk_widget_show(GTK_WIDGET(SCALE_ENTRY_SPINBUTTON(adj)));
1297		}
1298	      else
1299		{
1300		  gtk_widget_hide(GTK_WIDGET(SCALE_ENTRY_LABEL(adj)));
1301		  gtk_widget_hide(GTK_WIDGET(SCALE_ENTRY_SCALE(adj)));
1302		  gtk_widget_hide(GTK_WIDGET(SCALE_ENTRY_SPINBUTTON(adj)));
1303		}
1304	    }
1305	  break;
1306	case STP_PARAMETER_TYPE_CURVE:
1307	  if (opt->is_active && desc->p_level <= MAXIMUM_PARAMETER_LEVEL)
1308	    {
1309	      gtk_widget_show(GTK_WIDGET(opt->info.curve.label));
1310	      gtk_widget_show(GTK_WIDGET(opt->info.curve.button));
1311	    }
1312	  else
1313	    {
1314	      gtk_widget_hide(GTK_WIDGET(opt->info.curve.label));
1315	      gtk_widget_hide(GTK_WIDGET(opt->info.curve.button));
1316	      gtk_widget_hide(GTK_WIDGET(opt->info.curve.dialog));
1317	    }
1318	case STP_PARAMETER_TYPE_BOOLEAN:
1319	  if (opt->is_active && desc->p_level <= MAXIMUM_PARAMETER_LEVEL)
1320	    {
1321	      gtk_widget_show(GTK_WIDGET(opt->info.bool.checkbox));
1322	    }
1323	  else
1324	    {
1325	      gtk_widget_hide(GTK_WIDGET(opt->info.bool.checkbox));
1326	    }
1327	  break;
1328	case STP_PARAMETER_TYPE_FILE:
1329	  if (opt->is_active && desc->p_level <= MAXIMUM_PARAMETER_LEVEL)
1330	    {
1331	      gtk_widget_show(GTK_WIDGET(opt->info.file.f_label));
1332	      gtk_widget_show(GTK_WIDGET(opt->info.file.f_button));
1333	      gtk_widget_show(GTK_WIDGET(opt->info.file.f_entry));
1334	    }
1335	  else
1336	    {
1337	      gtk_widget_hide(GTK_WIDGET(opt->info.file.f_label));
1338	      gtk_widget_hide(GTK_WIDGET(opt->info.file.f_button));
1339	      gtk_widget_hide(GTK_WIDGET(opt->info.file.f_entry));
1340	      gtk_widget_hide(GTK_WIDGET(opt->info.file.f_browser));
1341	    }
1342	  break;
1343	default:
1344	  break;
1345	}
1346      if (!(opt->is_active) || desc->p_level > MAXIMUM_PARAMETER_LEVEL)
1347	{
1348	  if (opt->checkbox)
1349	    gtk_widget_hide(GTK_WIDGET(opt->checkbox));
1350	  if (opt->reset_btn)
1351	    gtk_widget_hide(GTK_WIDGET(opt->reset_btn));
1352	}
1353      else
1354	{
1355	  if (opt->checkbox)
1356	    {
1357	      if (!desc->is_mandatory)
1358		gtk_widget_show(GTK_WIDGET(opt->checkbox));
1359	      else
1360		gtk_widget_hide(GTK_WIDGET(opt->checkbox));
1361	    }
1362	  if (opt->reset_btn)
1363	    gtk_widget_show(GTK_WIDGET(opt->reset_btn));
1364	}
1365    }
1366}
1367
1368static void
1369color_button_callback(GtkWidget *widget, gpointer data)
1370{
1371  invalidate_preview_thumbnail();
1372  update_adjusted_thumbnail(TRUE);
1373}
1374
1375static void
1376create_top_level_structure(void)
1377{
1378  gchar *plug_in_name;
1379  /*
1380   * Create the main dialog
1381   */
1382
1383  plug_in_name = g_strdup_printf (_("%s -- Print v%s"),
1384                                  stpui_get_image_filename(),
1385				  VERSION " - " RELEASE_DATE);
1386
1387  print_dialog =
1388    stpui_dialog_new (plug_in_name,
1389		      GTK_WIN_POS_MOUSE,
1390		      TRUE,
1391
1392		      _("About"), about_callback,
1393		      NULL, NULL, NULL, FALSE, FALSE,
1394		      _("Print and\nSave Settings"), printandsave_callback,
1395		      NULL, NULL, NULL, FALSE, FALSE,
1396		      _("Save\nSettings"), save_callback,
1397		      NULL, NULL, NULL, FALSE, FALSE,
1398		      _("Print"), print_callback,
1399		      NULL, NULL, NULL, FALSE, FALSE,
1400		      _("Cancel"), gtk_widget_destroy,
1401		      NULL, (GObject *) 1, NULL, FALSE, TRUE,
1402
1403		      NULL);
1404
1405  g_free (plug_in_name);
1406
1407  g_signal_connect (G_OBJECT (print_dialog), "destroy",
1408		    G_CALLBACK (gtk_main_quit), NULL);
1409
1410  /*
1411   * Top-level containers
1412   */
1413
1414  main_vbox = gtk_vbox_new (FALSE, 2);
1415  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
1416  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (print_dialog)->vbox), main_vbox,
1417		      TRUE, TRUE, 0);
1418  gtk_widget_show (main_vbox);
1419
1420  main_hbox = gtk_hbox_new (FALSE, 4);
1421  gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, TRUE, TRUE, 0);
1422  gtk_widget_show (main_hbox);
1423
1424  right_vbox = gtk_vbox_new (FALSE, 2);
1425  gtk_box_pack_end (GTK_BOX (main_hbox), right_vbox, FALSE, FALSE, 0);
1426  gtk_widget_show (right_vbox);
1427
1428  notebook = gtk_notebook_new ();
1429  gtk_box_pack_start (GTK_BOX (right_vbox), notebook, TRUE, TRUE, 0);
1430  gtk_widget_show (notebook);
1431}
1432
1433static gint
1434drawing_area_resize_callback(GtkWidget *widget, GdkEventConfigure *event)
1435{
1436  preview_size_vert = event->height - 1;
1437  preview_size_horiz = event->width - 1;
1438  invalidate_preview_thumbnail();
1439  invalidate_frame();
1440  preview_update();
1441  return 1;
1442}
1443
1444static void
1445create_preview (void)
1446{
1447  GtkWidget *frame;
1448  GtkWidget *event_box;
1449
1450  frame = gtk_frame_new (_("Preview"));
1451  gtk_box_pack_start (GTK_BOX (main_hbox), frame, TRUE, TRUE, 0);
1452  gtk_widget_show (frame);
1453
1454  preview = (GtkDrawingArea *) gtk_drawing_area_new ();
1455  gtk_drawing_area_size(preview, preview_size_horiz + 1, preview_size_vert +1);
1456  g_signal_connect(G_OBJECT(preview), "configure_event",
1457		   G_CALLBACK(drawing_area_resize_callback), NULL);
1458  event_box = gtk_event_box_new ();
1459  gtk_container_add (GTK_CONTAINER (event_box), GTK_WIDGET (preview));
1460  gtk_container_add (GTK_CONTAINER (frame), event_box);
1461  gtk_widget_show (event_box);
1462
1463  g_signal_connect (G_OBJECT (preview), "expose_event",
1464		    G_CALLBACK (preview_expose), NULL);
1465  g_signal_connect (G_OBJECT (preview), "button_press_event",
1466		    G_CALLBACK (preview_button_callback), NULL);
1467  g_signal_connect (G_OBJECT (preview), "button_release_event",
1468		    G_CALLBACK (preview_button_callback), NULL);
1469  g_signal_connect (G_OBJECT (preview), "motion_notify_event",
1470		    G_CALLBACK (preview_motion_callback), NULL);
1471  gtk_widget_show (GTK_WIDGET (preview));
1472
1473  stpui_set_help_data
1474    (event_box,
1475     _("Position the image on the page.\n"
1476       "Click and drag with the primary button to position the image.\n"
1477       "Click and drag with the second button to move the image with finer precision; "
1478       "each unit of motion moves the image one point (1/72\")\n"
1479       "Click and drag with the third (middle) button to move the image in units of "
1480       "the image size.\n"
1481       "Holding down the shift key while clicking and dragging constrains the image to "
1482       "only horizontal or vertical motion.\n"
1483       "If you click another button while dragging the mouse, the image will return "
1484       "to its original position."));
1485
1486  gtk_widget_set_events (GTK_WIDGET (preview),
1487                         GDK_EXPOSURE_MASK | GDK_BUTTON_MOTION_MASK |
1488                         GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
1489}
1490
1491static GtkWidget *
1492create_positioning_entry(GtkWidget *table, int hpos, int vpos,
1493			 const char *text, const char *help)
1494{
1495  return stpui_create_entry
1496    (table, hpos, vpos, text, help, G_CALLBACK(position_callback));
1497}
1498
1499static GtkWidget *
1500create_positioning_button(GtkWidget *box, int invalid,
1501			  const char *text, const char *help)
1502{
1503  GtkWidget *button = gtk_button_new_with_label(gettext(text));
1504  gtk_box_pack_start(GTK_BOX(box), button, FALSE, TRUE, 0);
1505  gtk_widget_show(button);
1506  stpui_set_help_data(button, help);
1507  g_signal_connect(G_OBJECT(button), "clicked",
1508		     G_CALLBACK(position_button_callback),
1509		     (gpointer) invalid);
1510  return button;
1511}
1512
1513static void
1514create_paper_size_frame(void)
1515{
1516  GtkWidget *frame;
1517  GtkWidget *vbox;
1518  GtkWidget *media_size_table;
1519  GtkWidget *table;
1520  int vpos = 0;
1521
1522  frame = gtk_frame_new (_("Paper Size"));
1523  gtk_box_pack_start (GTK_BOX (right_vbox), frame, FALSE, TRUE, 0);
1524  gtk_widget_show (frame);
1525
1526  vbox = gtk_vbox_new (FALSE, 2);
1527  gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
1528  gtk_container_add (GTK_CONTAINER (frame), vbox);
1529  gtk_widget_show (vbox);
1530
1531  table = gtk_table_new (1, 1, FALSE);
1532  gtk_container_add (GTK_CONTAINER (vbox), table);
1533  gtk_widget_show (table);
1534
1535  /*
1536   * Media size combo box.
1537   */
1538
1539  page_size_table = gtk_table_new(1, 1, FALSE);
1540  gtk_widget_show (page_size_table);
1541  gtk_table_attach_defaults(GTK_TABLE(table), page_size_table,
1542			    0, 2, vpos, vpos + 1);
1543  vpos++;
1544  show_all_paper_sizes_button =
1545    gtk_check_button_new_with_label(_("Show All Paper Sizes"));
1546  gtk_table_attach_defaults
1547    (GTK_TABLE(table), show_all_paper_sizes_button, 0, 2, vpos, vpos + 1);
1548  gtk_toggle_button_set_active
1549    (GTK_TOGGLE_BUTTON(show_all_paper_sizes_button),
1550     stpui_show_all_paper_sizes);
1551  g_signal_connect(G_OBJECT(show_all_paper_sizes_button), "toggled",
1552		   G_CALLBACK(show_all_paper_sizes_callback), NULL);
1553  gtk_widget_show(show_all_paper_sizes_button);
1554  vpos++;
1555
1556  /*
1557   * Custom media size entries
1558   */
1559
1560  media_size_table = gtk_table_new (1, 1, FALSE);
1561  stpui_table_attach_aligned(GTK_TABLE (table), 0, vpos++, _("Dimensions:"),
1562			     0.0, 0.5, media_size_table, 1, TRUE);
1563  gtk_table_set_col_spacings (GTK_TABLE (media_size_table), 4);
1564
1565  custom_size_width = stpui_create_entry
1566    (media_size_table, 0, 3, _("Width:"),
1567     _("Width of the paper that you wish to print to"),
1568     G_CALLBACK(custom_media_size_callback));
1569
1570  custom_size_height = stpui_create_entry
1571    (media_size_table, 2, 3, _("Height:"),
1572     _("Height of the paper that you wish to print to"),
1573     G_CALLBACK(custom_media_size_callback));
1574
1575  vpos++;
1576  auto_paper_size_button =
1577    gtk_check_button_new_with_label(_("Automatic Paper Size"));
1578  gtk_table_attach_defaults
1579    (GTK_TABLE(table), auto_paper_size_button, 0, 2, vpos, vpos + 1);
1580  gtk_toggle_button_set_active
1581    (GTK_TOGGLE_BUTTON(auto_paper_size_button), FALSE);
1582  g_signal_connect(G_OBJECT(auto_paper_size_button), "toggled",
1583		   G_CALLBACK(auto_paper_size_callback), NULL);
1584}
1585
1586static void
1587create_copy_number_frame(void)
1588{
1589  GtkWidget *frame;
1590  GtkWidget *vbox;
1591  GtkWidget *event_box;
1592  GtkAdjustment *adj;
1593
1594  frame = gtk_frame_new (_("Number of Copies"));
1595  gtk_box_pack_start (GTK_BOX (right_vbox), frame, FALSE, TRUE, 0);
1596  gtk_widget_show (frame);
1597
1598  vbox = gtk_hbox_new (FALSE, 2);
1599  gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
1600  gtk_container_add (GTK_CONTAINER (frame), vbox);
1601  gtk_widget_show (vbox);
1602
1603  event_box = gtk_event_box_new ();
1604  gtk_container_add (GTK_CONTAINER (vbox), event_box);
1605  stpui_set_help_data(event_box,
1606		      _("Select the number of copies to print; "
1607			"a value between 1 and 100"));
1608  gtk_widget_show (event_box);
1609
1610  /*
1611   * Number of Copies Spin Button
1612   */
1613
1614  adj = (GtkAdjustment *) gtk_adjustment_new (1.0f, 1.0f, 100.0f,
1615					      1.0f, 5.0f, 0.0f);
1616  copy_count_spin_button = gtk_spin_button_new (adj, 0, 0);
1617  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (copy_count_spin_button), FALSE);
1618  gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (copy_count_spin_button), TRUE);
1619  gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (copy_count_spin_button),
1620				     GTK_UPDATE_IF_VALID);
1621
1622  g_signal_connect(G_OBJECT (adj), "value_changed",
1623		   G_CALLBACK (copy_count_callback),
1624		   NULL);
1625
1626  gtk_container_add (GTK_CONTAINER (event_box), copy_count_spin_button);
1627  gtk_widget_show(copy_count_spin_button);
1628}
1629
1630static void
1631create_positioning_frame (void)
1632{
1633  GtkWidget *frame;
1634  GtkWidget *table;
1635  GtkWidget *box;
1636  GtkWidget *sep;
1637
1638  frame = gtk_frame_new (_("Image Position"));
1639  gtk_box_pack_start (GTK_BOX (right_vbox), frame, FALSE, TRUE, 0);
1640  gtk_widget_show (frame);
1641
1642  table = gtk_table_new (1, 1, FALSE);
1643  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
1644  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
1645  gtk_container_set_border_width (GTK_CONTAINER (table), 4);
1646  gtk_container_add (GTK_CONTAINER (frame), table);
1647  gtk_widget_show (table);
1648
1649  /*
1650   * Orientation option menu.
1651   */
1652
1653  orientation_menu =
1654    stpui_option_menu_new (FALSE,
1655			   _("Auto"), orientation_callback,
1656			   (gpointer) ORIENT_AUTO, NULL, NULL, 0,
1657			   _("Portrait"), orientation_callback,
1658			   (gpointer) ORIENT_PORTRAIT, NULL, NULL, 0,
1659			   _("Landscape"), orientation_callback,
1660			   (gpointer) ORIENT_LANDSCAPE, NULL, NULL, 0,
1661			   _("Upside down"), orientation_callback,
1662			   (gpointer) ORIENT_UPSIDEDOWN, NULL, NULL, 0,
1663			   _("Seascape"), orientation_callback,
1664			   (gpointer) ORIENT_SEASCAPE, NULL, NULL, 0,
1665			   NULL);
1666  stpui_set_help_data (orientation_menu,
1667		 _("Select the orientation: portrait, landscape, "
1668		   "upside down, or seascape (upside down landscape)"));
1669  stpui_table_attach_aligned (GTK_TABLE (table), 0, 0, _("Orientation:"),
1670			      1.0, 0.5, orientation_menu, 4, TRUE);
1671  sep = gtk_hseparator_new ();
1672  gtk_table_attach_defaults (GTK_TABLE (table), sep, 0, 6, 1, 2);
1673  gtk_widget_show (sep);
1674
1675  /*
1676   * Position entries
1677   */
1678
1679  left_entry = create_positioning_entry
1680    (table, 0, 2, _("Left:"),
1681     _("Distance from the left of the paper to the image"));
1682#if 0
1683  right_entry = create_positioning_entry
1684    (table, 0, 3, _("Right:"),
1685     _("Distance from the left of the paper to the right of the image"));
1686#endif
1687  right_border_entry = create_positioning_entry
1688    (table, 0, 4, _("Right:"),
1689     _("Distance from the right of the paper to the image"));
1690  top_entry = create_positioning_entry
1691    (table, 3, 2, _("Top:"),
1692     _("Distance from the top of the paper to the image"));
1693#if 0
1694  bottom_entry = create_positioning_entry
1695    (table, 3, 3, _("Bottom:"),
1696     _("Distance from the top of the paper to bottom of the image"));
1697#endif
1698  bottom_border_entry = create_positioning_entry
1699    (table, 3, 4, _("Bottom:"),
1700     _("Distance from the bottom of the paper to the image"));
1701  /*
1702   * Center options
1703   */
1704
1705  sep = gtk_hseparator_new ();
1706  gtk_table_attach_defaults (GTK_TABLE (table), sep, 0, 6, 5, 6);
1707  gtk_widget_show (sep);
1708
1709  box = gtk_hbox_new (TRUE, 4);
1710  stpui_table_attach_aligned (GTK_TABLE (table), 0, 7, _("Center:"), 0.5, 0.5,
1711			      box, 5, TRUE);
1712  recenter_horizontal_button = create_positioning_button
1713    (box, INVALID_LEFT, _("Horizontal"),
1714     _("Center the image horizontally on the paper"));
1715  recenter_button = create_positioning_button
1716    (box, INVALID_LEFT | INVALID_TOP, _("Both"),
1717     _("Center the image on the paper"));
1718  recenter_vertical_button = create_positioning_button
1719    (box, INVALID_TOP, _("Vertical"),
1720     _("Center the image vertically on the paper"));
1721}
1722
1723static void
1724create_printer_dialog (void)
1725{
1726  GtkWidget *table;
1727  GtkWidget *label;
1728  GtkWidget *event_box;
1729  GSList    *group;
1730  gint       i;
1731  stp_string_list_t *manufacturer_list = stp_string_list_create();
1732
1733  setup_dialog = stpui_dialog_new(_("Setup Printer"),
1734				  GTK_WIN_POS_MOUSE, TRUE,
1735				  _("OK"), setup_ok_callback,
1736				  NULL, NULL, NULL, TRUE, FALSE,
1737				  _("Cancel"), setup_cancel_callback,
1738				  NULL, (GObject *) 1, NULL, FALSE, TRUE,
1739				  NULL);
1740
1741  /*
1742   * Top-level table for dialog.
1743   */
1744
1745  table = gtk_table_new (4, 4, FALSE);
1746  gtk_container_set_border_width (GTK_CONTAINER (table), 6);
1747  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
1748  gtk_table_set_row_spacing (GTK_TABLE (table), 0, 150);
1749  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (setup_dialog)->vbox), table,
1750                      TRUE, TRUE, 0);
1751  gtk_widget_show (table);
1752
1753  /*
1754   * Printer driver option menu.
1755   */
1756
1757  label = gtk_label_new (_("Printer Make:"));
1758  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
1759  gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 2,
1760		    GTK_FILL, GTK_FILL, 0, 0);
1761  gtk_widget_show (label);
1762
1763  event_box = gtk_event_box_new ();
1764  gtk_table_attach (GTK_TABLE (table), event_box, 2, 4, 0, 2,
1765                    GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
1766  gtk_widget_show (event_box);
1767
1768  stpui_set_help_data (event_box, _("Select the make of your printer"));
1769
1770  manufacturer_crawler = gtk_scrolled_window_new (NULL, NULL);
1771  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (manufacturer_crawler),
1772                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1773  gtk_container_add (GTK_CONTAINER (event_box), manufacturer_crawler);
1774  gtk_widget_show (manufacturer_crawler);
1775
1776  manufacturer_clist = gtk_clist_new (1);
1777  gtk_widget_set_usize (manufacturer_clist, 200, 0);
1778  gtk_clist_set_selection_mode(GTK_CLIST(manufacturer_clist),GTK_SELECTION_SINGLE);
1779  gtk_container_add (GTK_CONTAINER (manufacturer_crawler), manufacturer_clist);
1780  gtk_widget_show (manufacturer_clist);
1781
1782  g_signal_connect (G_OBJECT (manufacturer_clist), "select_row",
1783		    G_CALLBACK (manufacturer_callback), NULL);
1784
1785
1786  label = gtk_label_new (_("Printer Model:"));
1787  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
1788  gtk_table_attach (GTK_TABLE (table), label, 4, 5, 0, 2,
1789		    GTK_FILL, GTK_FILL, 0, 0);
1790  gtk_widget_show (label);
1791
1792  event_box = gtk_event_box_new ();
1793  gtk_table_attach (GTK_TABLE (table), event_box, 5, 7, 0, 2,
1794                    GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
1795  gtk_widget_show (event_box);
1796
1797  stpui_set_help_data (event_box, _("Select your printer model"));
1798
1799  printer_crawler = gtk_scrolled_window_new (NULL, NULL);
1800  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (printer_crawler),
1801                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1802  gtk_container_add (GTK_CONTAINER (event_box), printer_crawler);
1803  gtk_widget_show (printer_crawler);
1804
1805  printer_driver = gtk_clist_new (1);
1806  gtk_widget_set_usize (printer_driver, 200, 0);
1807  gtk_clist_set_selection_mode(GTK_CLIST(printer_driver),GTK_SELECTION_SINGLE);
1808  gtk_container_add (GTK_CONTAINER (printer_crawler), printer_driver);
1809  gtk_widget_show (printer_driver);
1810
1811  g_signal_connect (G_OBJECT (printer_driver), "select_row",
1812		    G_CALLBACK (print_driver_callback), NULL);
1813
1814
1815  for (i = 0; i < stp_printer_model_count (); i ++)
1816    {
1817      const stp_printer_t *the_printer = stp_get_printer_by_index (i);
1818
1819      if (strcmp(stp_printer_get_long_name (the_printer), "") != 0 &&
1820	  strcmp(stp_printer_get_family(the_printer), "raw") != 0)
1821	{
1822	  const gchar *make = stp_printer_get_manufacturer(the_printer);
1823	  if (! stp_string_list_is_present(manufacturer_list, make))
1824	    stp_string_list_add_string(manufacturer_list, make, make);
1825	}
1826    }
1827
1828  for (i = 0; i < stp_string_list_count(manufacturer_list); i++)
1829    {
1830      const stp_param_string_t *param =
1831	stp_string_list_param(manufacturer_list, i);
1832      gchar *xname = g_strdup(param->name);
1833      gtk_clist_insert(GTK_CLIST(manufacturer_clist), i, &xname);
1834      gtk_clist_set_row_data_full(GTK_CLIST(manufacturer_clist), i, xname,
1835				  g_free);
1836    }
1837  stp_string_list_destroy(manufacturer_list);
1838  gtk_clist_sort(GTK_CLIST(manufacturer_clist));
1839  build_printer_driver_clist();
1840
1841  /*
1842   * PPD file.
1843   */
1844
1845  ppd_label = gtk_label_new (_("PPD File:"));
1846  gtk_misc_set_alignment (GTK_MISC (ppd_label), 1.0, 0.5);
1847  gtk_table_attach (GTK_TABLE (table), ppd_label, 1, 2, 3, 4,
1848                    GTK_FILL, GTK_FILL, 0, 0);
1849  gtk_widget_show (ppd_label);
1850
1851  ppd_box = gtk_hbox_new (FALSE, 8);
1852  gtk_table_attach (GTK_TABLE (table), ppd_box, 2, 7, 3, 4,
1853                    GTK_FILL, GTK_FILL, 0, 0);
1854
1855  ppd_file = gtk_entry_new ();
1856  g_signal_connect(G_OBJECT(ppd_file), "activate",
1857		   G_CALLBACK(ppd_file_callback), NULL);
1858  gtk_box_pack_start (GTK_BOX (ppd_box), ppd_file, TRUE, TRUE, 0);
1859  gtk_widget_show (ppd_file);
1860
1861  stpui_set_help_data(ppd_file,_("Enter the correct PPD filename for your printer"));
1862
1863  ppd_button = gtk_button_new_with_label (_("Browse"));
1864  gtk_misc_set_padding (GTK_MISC (GTK_BIN (ppd_button)->child), 2, 0);
1865  gtk_box_pack_start (GTK_BOX (ppd_box), ppd_button, FALSE, FALSE, 0);
1866  gtk_widget_show (ppd_button);
1867  gtk_widget_show (ppd_box);
1868
1869  stpui_set_help_data(ppd_button,
1870		_("Choose the correct PPD filename for your printer"));
1871  g_signal_connect (G_OBJECT (ppd_button), "clicked",
1872		    G_CALLBACK (ppd_browse_callback), NULL);
1873
1874  ppd_model_label = gtk_label_new (_("Printer Model:"));
1875  gtk_misc_set_alignment (GTK_MISC (ppd_model_label), 1.0, 0.5);
1876  gtk_table_attach (GTK_TABLE (table), ppd_model_label, 1, 2, 4, 5,
1877                    GTK_FILL, GTK_FILL, 0, 0);
1878  gtk_widget_show (ppd_model_label);
1879
1880  ppd_model = gtk_label_new ("");
1881  gtk_misc_set_alignment (GTK_MISC (ppd_model), 0.0, 0.5);
1882  gtk_table_attach (GTK_TABLE (table), ppd_model, 2, 7, 4, 5,
1883                    GTK_FILL, GTK_FILL, 0, 0);
1884  gtk_widget_show (ppd_model);
1885
1886
1887  /*
1888   * Print command.
1889   */
1890
1891  group = NULL;
1892  for (i = 0; i < command_options_count; i++)
1893    group = stpui_create_radio_button(&(command_options[i]), group, table,
1894				      0, i > 0 ? i + 6 : i + 5,
1895				      G_CALLBACK(command_type_callback));
1896
1897  standard_cmd_entry = gtk_entry_new();
1898  gtk_table_attach (GTK_TABLE (table), standard_cmd_entry, 2, 7, 6, 7,
1899                    GTK_FILL, GTK_FILL, 0, 0);
1900  gtk_entry_set_editable(GTK_ENTRY(standard_cmd_entry), FALSE);
1901  gtk_widget_set_sensitive(standard_cmd_entry, FALSE);
1902  gtk_widget_show (standard_cmd_entry);
1903
1904  queue_combo = gtk_combo_new ();
1905  event_box = gtk_event_box_new ();
1906  gtk_container_add (GTK_CONTAINER (event_box), queue_combo);
1907  gtk_widget_show (queue_combo);
1908  gtk_widget_show (event_box);
1909  build_queue_combo();
1910
1911  stpui_set_help_data(event_box,
1912		      _("Select the name of the output queue (not the type, "
1913			"or model, of printer) that you wish to print to"));
1914  label = gtk_label_new(_("Printer Queue:"));
1915  gtk_widget_show(label);
1916  gtk_table_attach (GTK_TABLE (table), label, 2, 3, 5, 6,
1917                    GTK_FILL, GTK_FILL, 0, 0);
1918  gtk_table_attach (GTK_TABLE (table), event_box, 3, 7, 5, 6,
1919                    GTK_FILL, GTK_FILL, 0, 0);
1920
1921  custom_command_entry = gtk_entry_new ();
1922  gtk_table_attach (GTK_TABLE (table), custom_command_entry, 2, 7, 7, 8,
1923                    GTK_FILL, GTK_FILL, 0, 0);
1924  g_signal_connect(G_OBJECT(custom_command_entry), "activate",
1925		   G_CALLBACK(setup_callback), NULL);
1926  gtk_widget_set_sensitive(custom_command_entry, FALSE);
1927  gtk_widget_show (custom_command_entry);
1928
1929  stpui_set_help_data
1930    (custom_command_entry, _("Enter the correct command to print to your printer. "));
1931
1932  file_entry = gtk_entry_new ();
1933  gtk_table_attach (GTK_TABLE (table), file_entry, 2, 6, 8, 9,
1934                    GTK_FILL, GTK_FILL, 0, 0);
1935  g_signal_connect(G_OBJECT(file_entry), "activate",
1936		   G_CALLBACK(setup_callback), NULL);
1937  gtk_widget_show (file_entry);
1938
1939  gtk_widget_set_sensitive(file_entry, FALSE);
1940  stpui_set_help_data
1941    (file_entry, _("Enter the file to print to. "));
1942
1943  file_button = gtk_button_new_with_label (_("Browse"));
1944
1945  gtk_table_attach (GTK_TABLE (table), file_button, 6, 7, 8, 9,
1946                    GTK_FILL, GTK_FILL, 0, 0);
1947  gtk_widget_show (file_button);
1948
1949  stpui_set_help_data(file_button, _("File to print to"));
1950  g_signal_connect (G_OBJECT (file_button), "clicked",
1951		    G_CALLBACK (file_browse_callback), NULL);
1952
1953  /*
1954   * Output file selection dialog.
1955   */
1956
1957  file_browser = gtk_file_selection_new (_("Print To File"));
1958
1959  g_signal_connect
1960    (G_OBJECT (GTK_FILE_SELECTION (file_browser)->ok_button), "clicked",
1961     G_CALLBACK (file_ok_callback), NULL);
1962  g_signal_connect
1963    (G_OBJECT (GTK_FILE_SELECTION (file_browser)->cancel_button), "clicked",
1964     G_CALLBACK (file_cancel_callback), NULL);
1965
1966  /*
1967   * PPD file selection dialog.
1968   */
1969
1970  ppd_browser = gtk_file_selection_new (_("PPD File"));
1971  gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (ppd_browser));
1972
1973  g_signal_connect
1974    (G_OBJECT (GTK_FILE_SELECTION (ppd_browser)->ok_button), "clicked",
1975     G_CALLBACK (ppd_ok_callback), NULL);
1976  g_signal_connect_object
1977    (G_OBJECT (GTK_FILE_SELECTION (ppd_browser)->cancel_button), "clicked",
1978     G_CALLBACK (gtk_widget_hide), G_OBJECT (ppd_browser), G_CONNECT_SWAPPED);
1979}
1980
1981static void
1982create_new_printer_dialog (void)
1983{
1984  GtkWidget *table;
1985
1986  new_printer_dialog =
1987    stpui_dialog_new (_("Define New Printer"),
1988		      GTK_WIN_POS_MOUSE, FALSE,
1989		      _("OK"), new_printer_ok_callback,
1990		      NULL, NULL, NULL, TRUE, FALSE,
1991		      _("Cancel"), gtk_widget_hide,
1992		      NULL, (GObject *) 1, NULL, FALSE, TRUE,
1993		      NULL);
1994
1995  table = gtk_table_new (1, 1, FALSE);
1996  gtk_container_set_border_width (GTK_CONTAINER (table), 6);
1997  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
1998  gtk_table_set_row_spacings (GTK_TABLE (table), 8);
1999  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (new_printer_dialog)->vbox), table,
2000                      FALSE, FALSE, 0);
2001  gtk_widget_show (table);
2002
2003  new_printer_entry = gtk_entry_new ();
2004  gtk_entry_set_max_length (GTK_ENTRY (new_printer_entry), 127);
2005  stpui_table_attach_aligned(GTK_TABLE (table), 0, 0, _("Printer Name:"), 1.0,
2006			     0.5, new_printer_entry, 1, TRUE);
2007
2008  stpui_set_help_data(new_printer_entry,
2009		_("Enter the name you wish to give this logical printer"));
2010  g_signal_connect (G_OBJECT (new_printer_entry), "activate",
2011		    G_CALLBACK (new_printer_ok_callback), NULL);
2012}
2013
2014static void
2015create_about_dialog (void)
2016{
2017  GtkWidget *label;
2018  about_dialog =
2019    stpui_dialog_new (_("About Gutenprint " PLUG_IN_VERSION),
2020		      GTK_WIN_POS_MOUSE, FALSE,
2021		      _("OK"), gtk_widget_hide,
2022		      NULL, (GObject *) 1, NULL, TRUE, TRUE,
2023		      NULL);
2024
2025  label = gtk_label_new
2026    (_("Gutenprint Version " PLUG_IN_VERSION "\n"
2027       "\n"
2028       "Copyright (C) 1997-2003 Michael Sweet, Robert Krawitz,\n"
2029       "and the rest of the Gutenprint Development Team.\n"
2030       "\n"
2031       "Please visit our web site at http://gimp-print.sourceforge.net.\n"
2032       "\n"
2033       "This program is free software; you can redistribute it and/or modify\n"
2034       "it under the terms of the GNU General Public License as published by\n"
2035       "the Free Software Foundation; either version 2 of the License, or\n"
2036       "(at your option) any later version.\n"
2037       "\n"
2038       "This program is distributed in the hope that it will be useful,\n"
2039       "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2040       "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
2041       "GNU General Public License for more details.\n"
2042       "\n"
2043       "You should have received a copy of the GNU General Public License\n"
2044       "along with this program; if not, write to the Free Software\n"
2045       "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  "
2046       "USA\n"));
2047
2048  gtk_misc_set_padding (GTK_MISC (label), 12, 4);
2049  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (about_dialog)->vbox), label,
2050                      FALSE, FALSE, 0);
2051  gtk_widget_show (label);
2052}
2053
2054static void
2055create_printer_settings_frame (void)
2056{
2057  GtkWidget *table;
2058  GtkWidget *sep;
2059  GtkWidget *printer_hbox;
2060  GtkWidget *button;
2061  GtkWidget *event_box;
2062  GtkWidget *scrolled_window;
2063  gint vpos = 0;
2064
2065  create_printer_dialog ();
2066  create_about_dialog ();
2067  create_new_printer_dialog ();
2068
2069  table = gtk_table_new (1, 1, FALSE);
2070  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
2071  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
2072  gtk_container_set_border_width (GTK_CONTAINER (table), 4);
2073  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), table,
2074                            gtk_label_new (_("Printer Settings")));
2075  gtk_widget_show (table);
2076
2077  /*
2078   * Printer option menu.
2079   */
2080
2081  printer_combo = gtk_combo_new ();
2082  event_box = gtk_event_box_new ();
2083  gtk_container_add (GTK_CONTAINER (event_box), printer_combo);
2084  gtk_widget_show (printer_combo);
2085
2086  stpui_set_help_data(event_box,
2087		_("Select the name of the printer (not the type, "
2088		  "or model, of printer) that you wish to print to"));
2089  stpui_table_attach_aligned(GTK_TABLE (table), 0, vpos++, _("Printer Name:"),
2090			     0.0, 0.5, event_box, 1, TRUE);
2091  printer_model_label = gtk_label_new ("");
2092  stpui_table_attach_aligned(GTK_TABLE (table), 0, vpos++, _("Printer Model:"),
2093			     0.0, 0.0, printer_model_label, 1, TRUE);
2094  printer_hbox = gtk_hbox_new (TRUE, 4);
2095  gtk_table_attach (GTK_TABLE (table), printer_hbox,
2096		    1, 4, vpos, vpos + 1, GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0);
2097  vpos += 2;
2098  gtk_widget_show (printer_hbox);
2099
2100  /*
2101   * Setup printer button
2102   */
2103
2104  button = gtk_button_new_with_label (_("Setup Printer..."));
2105  stpui_set_help_data(button,
2106		      _("Choose the printer model, PPD file, and command "
2107			"that is used to print to this printer"));
2108  gtk_misc_set_padding (GTK_MISC (GTK_BIN (button)->child), 2, 0);
2109  gtk_box_pack_start (GTK_BOX (printer_hbox), button, FALSE, TRUE, 0);
2110  gtk_widget_show (button);
2111
2112  g_signal_connect (G_OBJECT (button), "clicked",
2113		    G_CALLBACK (setup_open_callback), NULL);
2114
2115  /*
2116   * New printer button
2117   */
2118
2119  button = gtk_button_new_with_label (_("New Printer..."));
2120  stpui_set_help_data (button, _("Define a new logical printer. This can be used to "
2121			   "name a collection of settings that you wish to "
2122			   "remember for future use."));
2123  gtk_box_pack_start (GTK_BOX (printer_hbox), button, FALSE, TRUE, 0);
2124  gtk_widget_show (button);
2125
2126  g_signal_connect (G_OBJECT (button), "clicked",
2127		    G_CALLBACK (new_printer_open_callback), NULL);
2128
2129  sep = gtk_hseparator_new ();
2130  gtk_table_attach (GTK_TABLE (table), sep, 0, 5, vpos, vpos + 1,
2131		    GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0);
2132  gtk_widget_show (sep);
2133  vpos++;
2134
2135  printer_features_table = gtk_table_new(1, 1, FALSE);
2136  gtk_table_set_col_spacings (GTK_TABLE (printer_features_table), 2);
2137  gtk_table_set_row_spacings (GTK_TABLE (printer_features_table), 0);
2138  gtk_widget_show (printer_features_table);
2139
2140  scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2141  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2142				 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
2143  gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window),
2144					printer_features_table);
2145  gtk_table_attach_defaults(GTK_TABLE(table), scrolled_window,
2146			    0, 6, vpos, vpos + 1);
2147  gtk_widget_show(scrolled_window);
2148  vpos++;
2149
2150  button = gtk_button_new_with_label (_("Set Printer Option Defaults"));
2151  stpui_set_help_data (button, _("Set all printer options to their defaults"));
2152  gtk_table_attach(GTK_TABLE(table), button, 0, 6, vpos, vpos + 1,
2153		   GTK_EXPAND|GTK_FILL, GTK_SHRINK|GTK_FILL, 0, 0);
2154  gtk_widget_show (button);
2155
2156  g_signal_connect (G_OBJECT (button), "clicked",
2157		    G_CALLBACK (set_printer_defaults), NULL);
2158
2159}
2160
2161static void
2162create_scaling_frame (void)
2163{
2164  GtkWidget *frame;
2165  GtkWidget *vbox;
2166  GtkWidget *hbox;
2167  GtkWidget *table;
2168  GtkWidget *box;
2169  GtkWidget *label;
2170  GtkWidget *event_box;
2171  GtkWidget *sep;
2172  GSList    *group;
2173
2174  frame = gtk_frame_new (_("Image Size"));
2175  gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
2176  gtk_widget_show (frame);
2177
2178  hbox = gtk_hbox_new (FALSE, 2);
2179  gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
2180  gtk_container_add (GTK_CONTAINER (frame), hbox);
2181  gtk_widget_show (hbox);
2182
2183  vbox = gtk_vbox_new (FALSE, 2);
2184/*  gtk_container_set_border_width (GTK_CONTAINER (vbox), 4); */
2185  gtk_container_add (GTK_CONTAINER (hbox), vbox);
2186  gtk_widget_show (vbox);
2187
2188  table = gtk_table_new (1, 1, FALSE);
2189  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
2190  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
2191  gtk_widget_show (table);
2192
2193  /*
2194   * Create the scaling adjustment using percent.  It doesn't really matter,
2195   * since as soon as we call plist_callback at the end of initialization
2196   * everything will be put right.
2197   */
2198  scaling_adjustment =
2199    stpui_scale_entry_new (GTK_TABLE (table), 0, 0, _("Scaling:"), 100, 75,
2200			   100.0, minimum_image_percent, 100.0,
2201			   1.0, 10.0, 1, TRUE, 0, 0, NULL);
2202  stpui_set_adjustment_tooltip(scaling_adjustment,
2203			       _("Set the scale (size) of the image"));
2204  g_signal_connect (G_OBJECT (scaling_adjustment), "value_changed",
2205		    G_CALLBACK (scaling_update), NULL);
2206
2207  box = gtk_hbox_new (FALSE, 4);
2208  gtk_box_pack_start (GTK_BOX (vbox), box, TRUE, TRUE, 0);
2209  gtk_widget_show (box);
2210
2211  /*
2212   * The scale by percent/ppi toggles
2213   */
2214
2215  table = gtk_table_new (1, 1, FALSE);
2216  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
2217  gtk_box_pack_start (GTK_BOX (box), table, FALSE, FALSE, 0);
2218  gtk_widget_show (table);
2219
2220  event_box = gtk_event_box_new ();
2221  gtk_table_attach (GTK_TABLE (table), event_box, 0, 1, 0, 1,
2222		    GTK_FILL, GTK_FILL, 0, 0);
2223  gtk_widget_show (event_box);
2224
2225  label = gtk_label_new (_("Scale by:"));
2226  gtk_container_add (GTK_CONTAINER (event_box), label);
2227  gtk_widget_show (label);
2228
2229  stpui_set_help_data(event_box,
2230		_("Select whether scaling is measured as percent of "
2231		  "available page size or number of output dots per inch"));
2232
2233  scaling_percent = gtk_radio_button_new_with_label (NULL, _("Percent"));
2234  group = gtk_radio_button_group (GTK_RADIO_BUTTON (scaling_percent));
2235  stpui_table_attach_aligned(GTK_TABLE (table), 0, 0, NULL, 0.5, 0.5,
2236			     scaling_percent, 2, TRUE);
2237
2238  stpui_set_help_data(scaling_percent, _("Scale the print to the size of the page"));
2239  g_signal_connect (G_OBJECT (scaling_percent), "toggled",
2240		    G_CALLBACK (scaling_callback), NULL);
2241
2242  scaling_ppi = gtk_radio_button_new_with_label (group, _("PPI"));
2243  stpui_table_attach_aligned(GTK_TABLE (table), 2, 0, NULL, 0.5, 0.5,
2244			     scaling_ppi, 1, TRUE);
2245
2246  stpui_set_help_data(scaling_ppi,
2247		_("Scale the print to the number of dots per inch"));
2248  g_signal_connect (G_OBJECT (scaling_ppi), "toggled",
2249		    G_CALLBACK (scaling_callback), NULL);
2250
2251  sep = gtk_vseparator_new ();
2252  gtk_box_pack_start (GTK_BOX (hbox), sep, FALSE, FALSE, 8);
2253  gtk_widget_show (sep);
2254
2255  /*
2256   * The width/height enries
2257   */
2258
2259  table = gtk_table_new (1, 1, FALSE);
2260  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
2261  gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
2262  gtk_widget_show (table);
2263
2264  width_entry = create_positioning_entry
2265    (table, 0, 0, _("Width:"), _("Set the width of the print"));
2266  height_entry = create_positioning_entry
2267    (table, 0, 1, _("Height:"), _("Set the height of the print"));
2268
2269  /*
2270   * The "image size" button
2271   */
2272
2273  scaling_image = gtk_button_new_with_label (_("Use Original\nImage Size"));
2274  gtk_misc_set_padding (GTK_MISC (GTK_BIN (scaling_image)->child), 2, 2);
2275  gtk_box_pack_end (GTK_BOX (hbox), scaling_image, FALSE, FALSE, 0);
2276  gtk_widget_show (scaling_image);
2277
2278  stpui_set_help_data(scaling_image,
2279		_("Set the print size to the size of the image"));
2280  g_signal_connect (G_OBJECT (scaling_image), "clicked",
2281		    G_CALLBACK (scaling_callback), NULL);
2282}
2283
2284/*
2285 * create_color_adjust_window (void)
2286 *
2287 * NOTES:
2288 *   creates the color adjuster popup, allowing the user to adjust brightness,
2289 *   contrast, saturation, etc.
2290 */
2291static void
2292create_color_adjust_window (void)
2293{
2294  GtkWidget *table;
2295  GtkWidget *label;
2296  GtkWidget *event_box;
2297  GtkWidget *scrolled_window;
2298  gint x, y; /* Window dimensions */
2299
2300  initialize_thumbnail();
2301
2302  color_adjust_dialog =
2303    stpui_dialog_new(_("Print Color Adjust"),
2304		     GTK_WIN_POS_MOUSE, TRUE,
2305
2306		     _("Set Defaults"), set_color_defaults,
2307		     NULL, NULL, NULL, FALSE, FALSE,
2308		     _("Close"), gtk_widget_hide,
2309		     NULL, (GObject *) 1, NULL, TRUE, TRUE,
2310		     NULL);
2311
2312  table = gtk_table_new (1, 1, FALSE);
2313  gtk_container_set_border_width (GTK_CONTAINER (table), 6);
2314  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
2315  gtk_table_set_row_spacings (GTK_TABLE (table), 0);
2316/*  gtk_table_set_row_spacing (GTK_TABLE (table), 8, 6); */
2317
2318  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (color_adjust_dialog)->vbox),
2319		      table, TRUE, TRUE, 0);
2320  gtk_widget_show (table);
2321
2322  /*
2323   * Drawing area for color swatch feedback display...
2324   */
2325
2326  event_box = gtk_event_box_new ();
2327  gtk_widget_show (GTK_WIDGET (event_box));
2328  gtk_table_attach (GTK_TABLE (table), GTK_WIDGET (event_box),
2329                    0, 1, 0, 1, 0, 0, 0, 0);
2330
2331  swatch = (GtkDrawingArea *) gtk_drawing_area_new ();
2332  gtk_widget_set_events (GTK_WIDGET (swatch), GDK_EXPOSURE_MASK);
2333  gtk_drawing_area_size (swatch, thumbnail_w, thumbnail_h);
2334  gtk_container_add (GTK_CONTAINER (event_box), GTK_WIDGET (swatch));
2335  gtk_widget_show (GTK_WIDGET (swatch));
2336
2337  stpui_set_help_data (GTK_WIDGET (event_box), _("Image preview"));
2338  g_signal_connect (G_OBJECT (swatch), "expose_event",
2339		    G_CALLBACK (redraw_color_swatch),
2340		    NULL);
2341
2342  event_box = gtk_event_box_new ();
2343  gtk_widget_show (GTK_WIDGET (event_box));
2344  gtk_table_attach (GTK_TABLE (table), GTK_WIDGET (event_box),
2345                    1, 2, 0, 1, 0, 0, 0, 0);
2346
2347  output_color_vbox = gtk_vbox_new(TRUE, 0);
2348  gtk_container_add(GTK_CONTAINER(event_box), output_color_vbox);
2349  gtk_widget_show(GTK_WIDGET(output_color_vbox));
2350
2351  label = gtk_label_new(_("View Output Channels:"));
2352  gtk_box_pack_start(GTK_BOX(output_color_vbox), label, TRUE, TRUE, 0);
2353  gtk_widget_show(GTK_WIDGET(label));
2354
2355  cyan_button = gtk_toggle_button_new_with_label(_("Cyan"));
2356  gtk_box_pack_start(GTK_BOX(output_color_vbox), cyan_button, TRUE, TRUE, 0);
2357  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cyan_button), TRUE);
2358  gtk_widget_show(GTK_WIDGET(cyan_button));
2359  g_signal_connect (G_OBJECT (cyan_button), "toggled",
2360		    G_CALLBACK (color_button_callback), NULL);
2361
2362  magenta_button = gtk_toggle_button_new_with_label(_("Magenta"));
2363  gtk_box_pack_start(GTK_BOX(output_color_vbox), magenta_button, TRUE, TRUE,0);
2364  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(magenta_button), TRUE);
2365  gtk_widget_show(GTK_WIDGET(magenta_button));
2366  g_signal_connect (G_OBJECT (magenta_button), "toggled",
2367		    G_CALLBACK (color_button_callback), NULL);
2368
2369  yellow_button = gtk_toggle_button_new_with_label(_("Yellow"));
2370  gtk_box_pack_start(GTK_BOX(output_color_vbox), yellow_button, TRUE, TRUE, 0);
2371  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(yellow_button), TRUE);
2372  gtk_widget_show(GTK_WIDGET(yellow_button));
2373  g_signal_connect (G_OBJECT (yellow_button), "toggled",
2374		    G_CALLBACK (color_button_callback), NULL);
2375
2376  black_button = gtk_toggle_button_new_with_label(_("Black"));
2377  gtk_box_pack_start(GTK_BOX(output_color_vbox), black_button, TRUE, TRUE, 0);
2378  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(black_button), TRUE);
2379  gtk_widget_show(GTK_WIDGET(black_button));
2380  g_signal_connect (G_OBJECT (black_button), "toggled",
2381		    G_CALLBACK (color_button_callback), NULL);
2382
2383  red_button = gtk_toggle_button_new_with_label(_("Red"));
2384  gtk_box_pack_start(GTK_BOX(output_color_vbox), red_button, TRUE, TRUE, 0);
2385  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(red_button), TRUE);
2386  gtk_widget_show(GTK_WIDGET(red_button));
2387  g_signal_connect (G_OBJECT (red_button), "toggled",
2388		    G_CALLBACK (color_button_callback), NULL);
2389
2390  green_button = gtk_toggle_button_new_with_label(_("Green"));
2391  gtk_box_pack_start(GTK_BOX(output_color_vbox), green_button, TRUE, TRUE,0);
2392  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(green_button), TRUE);
2393  gtk_widget_show(GTK_WIDGET(green_button));
2394  g_signal_connect (G_OBJECT (green_button), "toggled",
2395		    G_CALLBACK (color_button_callback), NULL);
2396
2397  blue_button = gtk_toggle_button_new_with_label(_("Blue"));
2398  gtk_box_pack_start(GTK_BOX(output_color_vbox), blue_button, TRUE, TRUE, 0);
2399  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(blue_button), TRUE);
2400  gtk_widget_show(GTK_WIDGET(blue_button));
2401  g_signal_connect (G_OBJECT (blue_button), "toggled",
2402		    G_CALLBACK (color_button_callback), NULL);
2403
2404  color_adjustment_table = gtk_table_new(1, 1, FALSE);
2405  gtk_table_set_col_spacings (GTK_TABLE (color_adjustment_table), 2);
2406  gtk_table_set_row_spacings (GTK_TABLE (color_adjustment_table), 0);
2407  gtk_container_set_border_width (GTK_CONTAINER (color_adjustment_table), 4);
2408  gtk_widget_show (color_adjustment_table);
2409
2410  scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2411  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2412				 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
2413  gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window),
2414					color_adjustment_table);
2415  gtk_table_attach_defaults(GTK_TABLE(table), scrolled_window,
2416			    0, 2, 1, 2);
2417  gtk_widget_show(scrolled_window);
2418
2419  /* The initial size request does not account for the
2420     GtkScrolledWindow. */
2421  gtk_window_get_size(GTK_WINDOW(color_adjust_dialog), &x, &y);
2422  gtk_window_set_default_size(GTK_WINDOW(color_adjust_dialog), x, y+300);
2423}
2424
2425static void
2426create_image_settings_frame (void)
2427{
2428  GtkWidget *vbox;
2429  GtkWidget *hbox;
2430  GtkWidget *table;
2431  GtkWidget *label;
2432  GtkWidget *event_box;
2433  GtkWidget *sep;
2434  GSList    *group;
2435  gint i;
2436
2437  create_color_adjust_window ();
2438
2439  vbox = gtk_vbox_new (FALSE, 4);
2440  gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
2441  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox,
2442                            gtk_label_new (_("Output")));
2443  gtk_widget_show (vbox);
2444
2445  table = gtk_table_new (1, 1, FALSE);
2446  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
2447  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
2448  gtk_widget_show (table);
2449
2450  event_box = gtk_event_box_new ();
2451  gtk_table_attach (GTK_TABLE (table), event_box, 0, 1, 0, 1,
2452                    GTK_FILL, GTK_FILL, 0, 0);
2453  gtk_widget_show (event_box);
2454
2455  /*
2456   * Output type toggles.
2457   */
2458
2459  table = gtk_table_new (1, 1, FALSE);
2460  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
2461/*  gtk_table_set_row_spacing (GTK_TABLE (table), 2, 4); */
2462  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
2463  gtk_widget_show (table);
2464
2465  event_box = gtk_event_box_new ();
2466  gtk_table_attach (GTK_TABLE (table), event_box, 0, 1, 0, 1,
2467                    GTK_FILL, GTK_FILL, 0, 0);
2468  gtk_widget_show (event_box);
2469
2470  label = gtk_label_new (_("Output Type:"));
2471  gtk_container_add (GTK_CONTAINER (event_box), label);
2472  gtk_widget_show (label);
2473
2474  stpui_set_help_data(event_box, _("Select the desired output type"));
2475
2476  group = NULL;
2477  for (i = 0; i < output_type_count; i++)
2478    group = stpui_create_radio_button(&(output_types[i]), group, table, 0, i,
2479				      G_CALLBACK(output_type_callback));
2480
2481  sep = gtk_hseparator_new ();
2482  gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 0);
2483  gtk_widget_show (sep);
2484
2485  /*
2486   *  Color adjust button
2487   */
2488  hbox = gtk_hbox_new (FALSE, 4);
2489  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
2490  gtk_widget_show(hbox);
2491  label = gtk_label_new("");
2492  gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
2493  gtk_widget_show(label);
2494
2495  adjust_color_button = gtk_button_new_with_label (_("Adjust Output..."));
2496  gtk_misc_set_padding (GTK_MISC (GTK_BIN (adjust_color_button)->child), 4, 0);
2497  gtk_box_pack_start (GTK_BOX (hbox), adjust_color_button, FALSE, FALSE, 0);
2498  gtk_widget_show(adjust_color_button);
2499  label = gtk_label_new("");
2500  gtk_box_pack_end(GTK_BOX(hbox), label, TRUE, TRUE, 0);
2501  gtk_widget_show(label);
2502
2503  stpui_set_help_data(adjust_color_button,
2504		_("Adjust color balance, brightness, contrast, "
2505		  "saturation, and dither algorithm"));
2506  g_signal_connect_object (G_OBJECT (adjust_color_button), "clicked",
2507			   G_CALLBACK (gtk_widget_show),
2508			   G_OBJECT (color_adjust_dialog),
2509			   G_CONNECT_SWAPPED);
2510}
2511
2512static void
2513create_units_frame (void)
2514{
2515  GtkWidget *vbox;
2516  GtkWidget *table;
2517  GtkWidget *label;
2518  GtkWidget *event_box;
2519  GSList    *group;
2520  gint i;
2521
2522  units_hbox = gtk_hbox_new(FALSE, 0);
2523  label = gtk_label_new(_("Size Units:"));
2524  gtk_widget_show(label);
2525  gtk_box_pack_start(GTK_BOX(units_hbox), label, TRUE, TRUE, 0);
2526  units_label = gtk_label_new(_(" "));
2527  gtk_widget_show(units_label);
2528  gtk_box_pack_start(GTK_BOX(units_hbox), units_label, TRUE, TRUE, 0);
2529  gtk_widget_show(units_hbox);
2530
2531  vbox = gtk_vbox_new (FALSE, 4);
2532  gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
2533  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, units_hbox);
2534  gtk_widget_show (vbox);
2535
2536  /*
2537   * The units toggles
2538   */
2539
2540  table = gtk_table_new (1, 1, FALSE);
2541  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
2542  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
2543  gtk_widget_show (table);
2544
2545  event_box = gtk_event_box_new ();
2546  gtk_table_attach (GTK_TABLE (table), event_box, 0, 1, 0, 1,
2547                    GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
2548  gtk_widget_show (event_box);
2549
2550  label = gtk_label_new (_("Units:"));
2551  gtk_container_add (GTK_CONTAINER (event_box), label);
2552  gtk_widget_show (label);
2553
2554  stpui_set_help_data(event_box,
2555		_("Select the base unit of measurement for printing"));
2556
2557  group = NULL;
2558  for (i = 0; i < unit_count; i++)
2559    {
2560      unit_t *unit = &(units[i]);
2561      unit->checkbox = gtk_radio_button_new_with_label(group, gettext(unit->name));
2562      group = gtk_radio_button_group(GTK_RADIO_BUTTON(unit->checkbox));
2563      stpui_table_attach_aligned(GTK_TABLE(table), i / 2, i % 2, NULL, 0.5,
2564				 0.5, unit->checkbox, 1, TRUE);
2565      stpui_set_help_data(unit->checkbox, gettext(unit->help));
2566      g_signal_connect(G_OBJECT(unit->checkbox), "toggled",
2567		       G_CALLBACK(unit_callback), (gpointer) i);
2568    }
2569}
2570
2571/*
2572 *  create_main_window()
2573 */
2574static void
2575create_main_window (void)
2576{
2577  gint x, y; /* Window dimensions */
2578
2579  set_current_printer();
2580  manufacturer = stp_printer_get_manufacturer(stp_get_printer(pv->v));
2581  /*
2582   * Create the various dialog components.  Note that we're not
2583   * actually initializing the values at this point; that will be done after
2584   * the UI is fully created.
2585   */
2586
2587  stpui_help_init();
2588
2589  create_top_level_structure ();
2590
2591  create_preview ();
2592  create_printer_settings_frame ();
2593  create_units_frame();
2594  create_paper_size_frame();
2595  create_copy_number_frame();
2596  create_positioning_frame ();
2597  create_scaling_frame ();
2598  create_image_settings_frame ();
2599
2600  /*
2601   * Now actually set up the correct values in the dialog
2602   */
2603
2604  do_update_thumbnail = 1;
2605  build_printer_combo ();
2606  plist_callback (NULL, (gpointer) stpui_plist_current);
2607  update_adjusted_thumbnail (TRUE);
2608
2609  /* The initial size request does not account for the
2610     GtkScrolledWindow. */
2611  gtk_window_get_size(GTK_WINDOW(print_dialog), &x, &y);
2612  gtk_window_set_default_size(GTK_WINDOW(print_dialog), x, y+80);
2613
2614  gtk_widget_show (print_dialog);
2615}
2616
2617static void
2618set_entry_value(GtkWidget *entry, double value, int block)
2619{
2620  gchar s[255];
2621  gdouble unit_scaler = units[pv->unit].scale;
2622  const gchar *format = units[pv->unit].format;
2623
2624  g_snprintf(s, sizeof(s), format, value / unit_scaler);
2625  if (block)
2626    g_signal_handlers_block_matched (G_OBJECT (entry),
2627				     G_SIGNAL_MATCH_DATA,
2628				     0,
2629				     0,
2630				     NULL,
2631				     NULL,
2632				     NULL);
2633
2634  gtk_entry_set_text (GTK_ENTRY (entry), s);
2635  if (block)
2636    g_signal_handlers_unblock_matched (G_OBJECT (entry),
2637				       G_SIGNAL_MATCH_DATA,
2638				       0,
2639				       0,
2640				       NULL,
2641				       NULL,
2642				       NULL);
2643}
2644
2645static void
2646reset_preview(void)
2647{
2648  if (!suppress_preview_reset)
2649    {
2650      stpui_enable_help();
2651      buttons_pressed = preview_active = 0;
2652    }
2653}
2654
2655static void
2656invalidate_preview_thumbnail (void)
2657{
2658  preview_valid = FALSE;
2659}
2660
2661static void
2662invalidate_frame (void)
2663{
2664  frame_valid = FALSE;
2665}
2666
2667static void
2668compute_scaling_limits(gdouble *min_ppi_scaling, gdouble *max_ppi_scaling)
2669{
2670  if (auto_paper_size)
2671    {
2672      *min_ppi_scaling =
2673	FINCH * (gdouble) image_width / (gdouble) printable_width;
2674    }
2675  else
2676    {
2677      gdouble min_ppi_scaling1 =
2678	FINCH * (gdouble) image_width / (gdouble) printable_width;
2679      gdouble min_ppi_scaling2 =
2680	FINCH * (gdouble) image_height / (gdouble) printable_height;
2681
2682      if (min_ppi_scaling1 > min_ppi_scaling2)
2683	*min_ppi_scaling = min_ppi_scaling1;
2684      else
2685	*min_ppi_scaling = min_ppi_scaling2;
2686    }
2687
2688  *max_ppi_scaling = *min_ppi_scaling * 100 / minimum_image_percent;
2689  if (*max_ppi_scaling < image_xres)
2690    *max_ppi_scaling = image_xres;
2691  if (*max_ppi_scaling < image_yres)
2692    *max_ppi_scaling = image_yres;
2693  minimum_image_percent = *min_ppi_scaling * 100 / *max_ppi_scaling;
2694}
2695
2696/*
2697 *  scaling_update() - Update the scaling scale using the slider.
2698 */
2699static void
2700scaling_update (GtkAdjustment *adjustment)
2701{
2702  reset_preview ();
2703
2704  if (pv->scaling != adjustment->value)
2705    {
2706      invalidate_preview_thumbnail ();
2707      if (GTK_TOGGLE_BUTTON (scaling_ppi)->active)
2708	pv->scaling = -adjustment->value;
2709      else
2710	pv->scaling = adjustment->value;
2711
2712      suppress_scaling_adjustment = TRUE;
2713      preview_update ();
2714      suppress_scaling_adjustment = FALSE;
2715    }
2716}
2717
2718/*
2719 *  scaling_callback() - Update the scaling scale using radio buttons.
2720 */
2721static void
2722scaling_callback (GtkWidget *widget)
2723{
2724  gdouble max_ppi_scaling;
2725  gdouble min_ppi_scaling;
2726  gdouble current_scale;
2727
2728  reset_preview ();
2729
2730  if (suppress_scaling_callback)
2731    return;
2732
2733  compute_scaling_limits(&min_ppi_scaling, &max_ppi_scaling);
2734
2735  if (widget == scaling_ppi)
2736    {
2737      if (! GTK_TOGGLE_BUTTON (scaling_ppi)->active)
2738	return;
2739
2740      GTK_ADJUSTMENT (scaling_adjustment)->lower = min_ppi_scaling;
2741      GTK_ADJUSTMENT (scaling_adjustment)->upper = max_ppi_scaling;
2742
2743      /*
2744       * Compute the correct PPI to create an image of the same size
2745       * as the one measured in percent
2746       */
2747      current_scale = GTK_ADJUSTMENT (scaling_adjustment)->value;
2748      GTK_ADJUSTMENT (scaling_adjustment)->value =
2749	min_ppi_scaling / (current_scale / 100);
2750      pv->scaling = 0.0;
2751    }
2752  else if (widget == scaling_percent)
2753    {
2754      gdouble new_percent;
2755
2756      if (! GTK_TOGGLE_BUTTON (scaling_percent)->active)
2757	return;
2758
2759      current_scale = GTK_ADJUSTMENT (scaling_adjustment)->value;
2760      GTK_ADJUSTMENT (scaling_adjustment)->lower = minimum_image_percent;
2761      GTK_ADJUSTMENT (scaling_adjustment)->upper = 100.0;
2762
2763      new_percent = 100 * min_ppi_scaling / current_scale;
2764
2765      if (new_percent > 100)
2766	new_percent = 100;
2767      if (new_percent < minimum_image_percent)
2768	new_percent = minimum_image_percent;
2769
2770      GTK_ADJUSTMENT (scaling_adjustment)->value = new_percent;
2771      pv->scaling = 0.0;
2772    }
2773  else if (widget == scaling_image)
2774    {
2775      gdouble yres = image_yres;
2776
2777      invalidate_preview_thumbnail ();
2778
2779      GTK_ADJUSTMENT (scaling_adjustment)->lower = min_ppi_scaling;
2780      GTK_ADJUSTMENT (scaling_adjustment)->upper = max_ppi_scaling;
2781
2782      if (yres < min_ppi_scaling)
2783	yres = min_ppi_scaling;
2784      if (yres > max_ppi_scaling)
2785	yres = max_ppi_scaling;
2786
2787      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scaling_ppi), TRUE);
2788      GTK_ADJUSTMENT (scaling_adjustment)->value = yres;
2789      pv->scaling = 0.0;
2790    }
2791
2792  if (widget == scaling_ppi || widget == scaling_percent)
2793    suppress_preview_update++;
2794  gtk_adjustment_changed (GTK_ADJUSTMENT (scaling_adjustment));
2795  gtk_adjustment_value_changed (GTK_ADJUSTMENT (scaling_adjustment));
2796  if (auto_paper_size)
2797    set_media_size(stp_get_string_parameter(pv->v, "PageSize"));
2798  if (widget == scaling_ppi || widget == scaling_percent)
2799    suppress_preview_update--;
2800}
2801
2802/****************************************************************************
2803 *
2804 * plist_build_combo
2805 *
2806 ****************************************************************************/
2807static void
2808plist_build_combo (GtkWidget      *combo,       /* I - Combo widget */
2809		   GtkWidget      *label,
2810		   stp_string_list_t *items,    /* I - Menu items */
2811		   int		  active,
2812		   const gchar    *cur_item,    /* I - Current item */
2813		   const gchar    *def_value,   /* I - default item */
2814		   GCallback      callback,    /* I - Callback */
2815		   gint           *callback_id, /* IO - Callback ID (init to -1) */
2816		   int (*check_func)(const char *string),
2817		   gpointer        data)
2818{
2819  gint      i; /* Looping var */
2820  GList    *list = 0;
2821  gint num_items = 0;
2822  GtkEntry *entry = GTK_ENTRY (GTK_COMBO (combo)->entry);
2823
2824  if (check_func && items)
2825    {
2826      stp_string_list_t *new_items = stp_string_list_create();
2827      num_items = stp_string_list_count(items);
2828      for (i = 0; i < num_items; i++)
2829	{
2830	  stp_param_string_t *param = stp_string_list_param(items, i);
2831	  if ((*check_func)(param->name))
2832	    stp_string_list_add_string(new_items, param->name, param->text);
2833	}
2834      items = new_items;
2835    }
2836
2837  if (items)
2838    num_items = stp_string_list_count(items);
2839
2840  if (*callback_id != -1)
2841    g_signal_handler_disconnect (G_OBJECT (entry), *callback_id);
2842  gtk_entry_set_editable (entry, FALSE);
2843
2844  if (!active || num_items == 0)
2845    {
2846      list = g_list_append (list, _("Standard"));
2847      gtk_combo_set_popdown_strings (GTK_COMBO (combo), list);
2848      *callback_id = -1;
2849      gtk_widget_set_sensitive (combo, FALSE);
2850      gtk_widget_hide (combo);
2851      if (label)
2852	gtk_widget_hide(label);
2853      if (check_func && items)
2854	stp_string_list_destroy(items);
2855      return;
2856    }
2857
2858  for (i = 0; i < num_items; i ++)
2859    list = g_list_append(list, g_strdup(stp_string_list_param(items, i)->text));
2860
2861  gtk_combo_set_popdown_strings (GTK_COMBO (combo), list);
2862
2863  if (cur_item)
2864    for (i = 0; i < num_items; i ++)
2865      if (strcmp(stp_string_list_param(items, i)->name, cur_item) == 0)
2866	break;
2867
2868  if (i >= num_items && def_value)
2869    for (i = 0; i < num_items; i ++)
2870      if (strcmp(stp_string_list_param(items, i)->name, def_value) == 0)
2871	break;
2872
2873  if (i >= num_items)
2874    i = 0;
2875
2876  gtk_entry_set_text (entry, stp_string_list_param(items, i)->text);
2877
2878  gtk_combo_set_value_in_list (GTK_COMBO (combo), TRUE, FALSE);
2879  gtk_widget_set_sensitive (combo, TRUE);
2880  gtk_widget_show (combo);
2881  if (label)
2882    gtk_widget_show(label);
2883
2884  *callback_id = g_signal_connect (G_OBJECT (entry), "changed", callback,
2885				   data);
2886  if (check_func && items)
2887    stp_string_list_destroy(items);
2888}
2889
2890void
2891stpui_set_image_dimensions(gint width, gint height)
2892{
2893  image_true_width = width;
2894  image_true_height = height;
2895}
2896
2897void
2898stpui_set_image_resolution(gdouble xres, gdouble yres)
2899{
2900  image_xres = xres;
2901  image_yres = yres;
2902}
2903
2904gint
2905stpui_compute_orientation(void)
2906{
2907  if (auto_paper_size ||
2908      (printable_width >= printable_height &&
2909       image_true_width >= image_true_height) ||
2910      (printable_height >= printable_width &&
2911       image_true_height >= image_true_width))
2912    return ORIENT_PORTRAIT;
2913  else
2914    return ORIENT_LANDSCAPE;
2915}
2916
2917static void
2918compute_printable_region(void)
2919{
2920  stp_get_media_size(pv->v, &paper_width, &paper_height);
2921  stp_get_imageable_area(pv->v, &left, &right, &bottom, &top);
2922  printable_width  = right - left;
2923  printable_height = bottom - top;
2924}
2925
2926static void
2927set_orientation(int orientation)
2928{
2929  compute_printable_region();
2930  pv->orientation = orientation;
2931  if (orientation == ORIENT_AUTO)
2932    orientation = stpui_compute_orientation();
2933  physical_orientation = orientation;
2934  switch (orientation)
2935    {
2936    case ORIENT_PORTRAIT:
2937    case ORIENT_UPSIDEDOWN:
2938      image_height = image_true_height;
2939      image_width = image_true_width;
2940      preview_thumbnail_h = thumbnail_h;
2941      preview_thumbnail_w = thumbnail_w;
2942      break;
2943    case ORIENT_LANDSCAPE:
2944    case ORIENT_SEASCAPE:
2945      image_height = image_true_width;
2946      image_width = image_true_height;
2947      preview_thumbnail_h = thumbnail_w;
2948      preview_thumbnail_w = thumbnail_h;
2949      break;
2950    }
2951  update_adjusted_thumbnail(FALSE);
2952}
2953
2954static void
2955position_button_callback(GtkWidget *widget, gpointer data)
2956{
2957  reset_preview();
2958  pv->invalid_mask |= (gint) data;
2959  preview_update ();
2960}
2961
2962/*
2963 * position_callback() - callback for position entry widgets
2964 */
2965static void
2966position_callback (GtkWidget *widget)
2967{
2968  gdouble new_printed_value = atof (gtk_entry_get_text (GTK_ENTRY (widget)));
2969  gint new_value = SCALE(new_printed_value, units[pv->unit].scale);
2970
2971  reset_preview ();
2972  suppress_preview_update++;
2973
2974  if (widget == top_entry)
2975    stp_set_top(pv->v, new_value);
2976/*
2977  else if (widget == bottom_entry)
2978    stp_set_top(pv->v, new_value - print_height);
2979*/
2980  else if (widget == bottom_border_entry)
2981    stp_set_top (pv->v, paper_height - print_height - new_value);
2982  else if (widget == left_entry)
2983    stp_set_left (pv->v, new_value);
2984/*
2985  else if (widget == right_entry)
2986    stp_set_left(pv->v, new_value - print_width);
2987*/
2988  else if (widget == right_border_entry)
2989    stp_set_left (pv->v, paper_width - print_width - new_value);
2990  else if (widget == width_entry || widget == height_entry)
2991    {
2992      gboolean was_percent = (pv->scaling >= 0);
2993      if (pv->scaling >= 0)
2994	{
2995	  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scaling_ppi), TRUE);
2996	  scaling_callback (scaling_ppi);
2997	}
2998      if  (widget == width_entry)
2999	GTK_ADJUSTMENT (scaling_adjustment)->value =
3000	  ((gdouble) image_width) / (new_value / FINCH);
3001      else
3002	GTK_ADJUSTMENT (scaling_adjustment)->value =
3003	  ((gdouble) image_height) / (new_value / FINCH);
3004      gtk_adjustment_value_changed (GTK_ADJUSTMENT (scaling_adjustment));
3005      if (was_percent)
3006	{
3007	  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(scaling_percent),TRUE);
3008	  gtk_adjustment_value_changed(GTK_ADJUSTMENT (scaling_adjustment));
3009	}
3010    }
3011
3012  suppress_preview_update--;
3013  preview_update ();
3014}
3015
3016static void
3017set_adjustment_active(option_t *opt, gboolean active, gboolean do_toggle)
3018{
3019  GtkObject *adj = opt->info.flt.adjustment;
3020  if (do_toggle)
3021    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(opt->checkbox), active);
3022  gtk_widget_set_sensitive (GTK_WIDGET (SCALE_ENTRY_LABEL (adj)), active);
3023  gtk_widget_set_sensitive (GTK_WIDGET (SCALE_ENTRY_SCALE (adj)), active);
3024  gtk_widget_set_sensitive (GTK_WIDGET (SCALE_ENTRY_SPINBUTTON (adj)), active);
3025  gtk_widget_set_sensitive (GTK_WIDGET (opt->reset_btn), active);
3026}
3027
3028static void
3029set_combo_active(option_t *opt, gboolean active, gboolean do_toggle)
3030{
3031  if (do_toggle)
3032    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(opt->checkbox), active);
3033  gtk_widget_set_sensitive(GTK_WIDGET(opt->info.list.combo), active);
3034  gtk_widget_set_sensitive(GTK_WIDGET(opt->info.list.label), active);
3035  gtk_widget_set_sensitive (GTK_WIDGET (opt->reset_btn), active);
3036}
3037
3038static void
3039set_curve_active(option_t *opt, gboolean active, gboolean do_toggle)
3040{
3041  if (do_toggle)
3042    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(opt->checkbox), active);
3043  gtk_widget_set_sensitive(GTK_WIDGET(opt->info.curve.button), active);
3044  gtk_widget_set_sensitive(GTK_WIDGET(opt->info.curve.label), active);
3045  if (active)
3046    {
3047      if (opt->info.curve.is_visible)
3048	gtk_widget_show(GTK_WIDGET(opt->info.curve.dialog));
3049    }
3050  else
3051    gtk_widget_hide(GTK_WIDGET(opt->info.curve.dialog));
3052  gtk_widget_set_sensitive (GTK_WIDGET (opt->reset_btn), active);
3053}
3054
3055static void
3056set_bool_active(option_t *opt, gboolean active, gboolean do_toggle)
3057{
3058  if (do_toggle)
3059    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(opt->checkbox), active);
3060  gtk_widget_set_sensitive(GTK_WIDGET(opt->info.bool.checkbox), active);
3061  gtk_widget_set_sensitive (GTK_WIDGET (opt->reset_btn), active);
3062}
3063
3064static void
3065set_file_active(option_t *opt, gboolean active, gboolean do_toggle)
3066{
3067  if (do_toggle)
3068    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(opt->checkbox), active);
3069  gtk_widget_set_sensitive(GTK_WIDGET(opt->info.file.f_label), active);
3070  gtk_widget_set_sensitive(GTK_WIDGET(opt->info.file.f_button), active);
3071  gtk_widget_set_sensitive(GTK_WIDGET(opt->info.file.f_entry), active);
3072  if (active)
3073    {
3074      if (opt->info.file.f_is_visible)
3075	gtk_widget_show(GTK_WIDGET(opt->info.file.f_browser));
3076    }
3077  else
3078    gtk_widget_hide(GTK_WIDGET(opt->info.file.f_browser));
3079  gtk_widget_set_sensitive (GTK_WIDGET (opt->reset_btn), active);
3080}
3081
3082static void
3083do_color_updates (void)
3084{
3085  int i;
3086  for (i = 0; i < current_option_count; i++)
3087    {
3088      option_t *opt = &(current_options[i]);
3089      if (opt->fast_desc->p_level <= MAXIMUM_PARAMETER_LEVEL)
3090	{
3091	  switch (opt->fast_desc->p_type)
3092	    {
3093	    case STP_PARAMETER_TYPE_DOUBLE:
3094	      if (stp_check_float_parameter(pv->v, opt->fast_desc->name,
3095					    STP_PARAMETER_INACTIVE))
3096		gtk_adjustment_set_value
3097		  (GTK_ADJUSTMENT(opt->info.flt.adjustment),
3098		   stp_get_float_parameter(pv->v, opt->fast_desc->name));
3099	      if (stp_check_float_parameter(pv->v, opt->fast_desc->name,
3100					    STP_PARAMETER_ACTIVE) ||
3101		  opt->fast_desc->is_mandatory)
3102		set_adjustment_active(opt, TRUE, TRUE);
3103	      else
3104		set_adjustment_active(opt, FALSE, TRUE);
3105	      break;
3106	    case STP_PARAMETER_TYPE_DIMENSION:
3107	      if (stp_check_dimension_parameter(pv->v, opt->fast_desc->name,
3108						STP_PARAMETER_INACTIVE))
3109		{
3110		  gdouble unit_scaler = units[pv->unit].scale;
3111		  gtk_adjustment_set_value
3112		  (GTK_ADJUSTMENT(opt->info.flt.adjustment),
3113		   (stp_get_dimension_parameter(pv->v, opt->fast_desc->name) /
3114		    unit_scaler));
3115		}
3116	      if (stp_check_dimension_parameter(pv->v, opt->fast_desc->name,
3117						STP_PARAMETER_ACTIVE) ||
3118		  opt->fast_desc->is_mandatory)
3119		set_adjustment_active(opt, TRUE, TRUE);
3120	      else
3121		set_adjustment_active(opt, FALSE, TRUE);
3122	      break;
3123	    case STP_PARAMETER_TYPE_INT:
3124	      if (stp_check_int_parameter(pv->v, opt->fast_desc->name,
3125					  STP_PARAMETER_INACTIVE))
3126		{
3127		  gtk_adjustment_set_value
3128		  (GTK_ADJUSTMENT(opt->info.flt.adjustment),
3129		   (stp_get_int_parameter(pv->v, opt->fast_desc->name)));
3130		}
3131	      if (stp_check_int_parameter(pv->v, opt->fast_desc->name,
3132					  STP_PARAMETER_ACTIVE) ||
3133		  opt->fast_desc->is_mandatory)
3134		set_adjustment_active(opt, TRUE, TRUE);
3135	      else
3136		set_adjustment_active(opt, FALSE, TRUE);
3137	      break;
3138	    case STP_PARAMETER_TYPE_CURVE:
3139	      if (stp_check_curve_parameter(pv->v, opt->fast_desc->name,
3140					    STP_PARAMETER_ACTIVE) ||
3141		  opt->fast_desc->is_mandatory)
3142		set_curve_active(opt, TRUE, TRUE);
3143	      else
3144		set_curve_active(opt, FALSE, TRUE);
3145	      break;
3146	    case STP_PARAMETER_TYPE_STRING_LIST:
3147	      if (strcmp(opt->fast_desc->name, "PageSize") == 0)
3148		build_page_size_combo(opt);
3149	      else if (stp_check_string_parameter(pv->v, opt->fast_desc->name,
3150						  STP_PARAMETER_INACTIVE))
3151		plist_build_combo(opt->info.list.combo, opt->info.list.label,
3152				  opt->info.list.params, opt->is_active,
3153				  (stp_get_string_parameter
3154				   (pv->v, opt->fast_desc->name)),
3155				  opt->info.list.default_val,
3156				  G_CALLBACK(combo_callback),
3157				  &(opt->info.list.callback_id),
3158				  NULL, opt);
3159	      if (stp_check_string_parameter(pv->v, opt->fast_desc->name,
3160					     STP_PARAMETER_ACTIVE) ||
3161		  opt->fast_desc->is_mandatory)
3162		set_combo_active(opt, TRUE, TRUE);
3163	      else
3164		set_combo_active(opt, FALSE, TRUE);
3165	      break;
3166	    case STP_PARAMETER_TYPE_BOOLEAN:
3167	      if (stp_check_boolean_parameter(pv->v, opt->fast_desc->name,
3168					      STP_PARAMETER_INACTIVE))
3169		gtk_toggle_button_set_active
3170		  (GTK_TOGGLE_BUTTON(opt->info.bool.checkbox),
3171		   stp_get_boolean_parameter(pv->v, opt->fast_desc->name));
3172	      if (stp_check_boolean_parameter(pv->v, opt->fast_desc->name,
3173					      STP_PARAMETER_ACTIVE) ||
3174		  opt->fast_desc->is_mandatory)
3175		set_bool_active(opt, TRUE, TRUE);
3176	      else
3177		set_bool_active(opt, FALSE, TRUE);
3178	      break;
3179	    case STP_PARAMETER_TYPE_FILE:
3180	      if (stp_check_file_parameter(pv->v, opt->fast_desc->name,
3181					   STP_PARAMETER_ACTIVE) ||
3182		  opt->fast_desc->is_mandatory)
3183		set_file_active(opt, TRUE, TRUE);
3184	      else
3185		set_file_active(opt, FALSE, TRUE);
3186	      break;
3187	    default:
3188	      break;
3189	    }
3190	}
3191    }
3192  update_adjusted_thumbnail (TRUE);
3193}
3194
3195static void
3196update_options(void)
3197{
3198  gtk_widget_hide(page_size_table);
3199  gtk_widget_hide(printer_features_table);
3200  gtk_widget_hide(color_adjustment_table);
3201  populate_options(pv->v);
3202  populate_option_table(page_size_table, STP_PARAMETER_CLASS_CORE);
3203  populate_option_table(printer_features_table, STP_PARAMETER_CLASS_FEATURE);
3204  populate_option_table(color_adjustment_table, STP_PARAMETER_CLASS_OUTPUT);
3205  gtk_widget_show(page_size_table);
3206  gtk_widget_show(printer_features_table);
3207  gtk_widget_show(color_adjustment_table);
3208  set_options_active(NULL);
3209}
3210
3211static void
3212update_standard_print_command(void)
3213{
3214  char *label_text =
3215    stpui_build_standard_print_command(pv, stp_get_printer(pv->v));
3216  gtk_entry_set_text(GTK_ENTRY(standard_cmd_entry), label_text);
3217  g_free(label_text);
3218}
3219
3220static void
3221set_color_options(void)
3222{
3223  stp_parameter_t desc;
3224  stp_describe_parameter(pv->v, "PrintingMode", &desc);
3225  if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
3226    {
3227      if (!stp_string_list_is_present(desc.bounds.str, "Color"))
3228	{
3229	  gtk_widget_set_sensitive (output_types[1].button, TRUE);
3230	  if (gtk_toggle_button_get_active
3231	      (GTK_TOGGLE_BUTTON (output_types[0].button)) == TRUE)
3232	    gtk_toggle_button_set_active
3233	      (GTK_TOGGLE_BUTTON (output_types[1].button), TRUE);
3234	  gtk_widget_set_sensitive (output_types[0].button, FALSE);
3235	}
3236      else if (!stp_string_list_is_present(desc.bounds.str, "BW"))
3237	{
3238	  gtk_widget_set_sensitive (output_types[0].button, TRUE);
3239	  if (gtk_toggle_button_get_active
3240	      (GTK_TOGGLE_BUTTON (output_types[1].button)) == TRUE)
3241	    gtk_toggle_button_set_active
3242	      (GTK_TOGGLE_BUTTON (output_types[0].button), TRUE);
3243	  gtk_widget_set_sensitive (output_types[1].button, FALSE);
3244	}
3245      else
3246	{
3247	  gtk_widget_set_sensitive (output_types[0].button, TRUE);
3248	  gtk_widget_set_sensitive (output_types[1].button, TRUE);
3249	}
3250    }
3251  stp_parameter_description_destroy(&desc);
3252}
3253
3254static void
3255do_all_updates(void)
3256{
3257  gint i;
3258  suppress_preview_update++;
3259  set_orientation(pv->orientation);
3260  invalidate_preview_thumbnail ();
3261  preview_update ();
3262  update_standard_print_command();
3263
3264  if (pv->scaling < 0)
3265    {
3266      gdouble tmp = -pv->scaling;
3267      gdouble max_ppi_scaling;
3268      gdouble min_ppi_scaling;
3269
3270      compute_scaling_limits(&min_ppi_scaling, &max_ppi_scaling);
3271
3272      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scaling_ppi), TRUE);
3273      GTK_ADJUSTMENT (scaling_adjustment)->lower = min_ppi_scaling;
3274      GTK_ADJUSTMENT (scaling_adjustment)->upper = max_ppi_scaling;
3275      GTK_ADJUSTMENT (scaling_adjustment)->value = tmp;
3276      gtk_adjustment_changed (GTK_ADJUSTMENT (scaling_adjustment));
3277      gtk_adjustment_value_changed (GTK_ADJUSTMENT (scaling_adjustment));
3278    }
3279  else
3280    {
3281      gdouble tmp = pv->scaling;
3282
3283      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scaling_percent), TRUE);
3284      GTK_ADJUSTMENT (scaling_adjustment)->lower = minimum_image_percent;
3285      GTK_ADJUSTMENT (scaling_adjustment)->upper = 100.0;
3286      GTK_ADJUSTMENT (scaling_adjustment)->value = tmp;
3287      g_signal_emit_by_name (G_OBJECT(scaling_adjustment), "changed");
3288      g_signal_emit_by_name (G_OBJECT(scaling_adjustment), "value_changed");
3289    }
3290
3291  set_color_options();
3292  for (i = 0; i < output_type_count; i++)
3293    {
3294      if (stp_get_string_parameter(pv->v, "PrintingMode") &&
3295	  strcmp(output_types[i].value,
3296		 stp_get_string_parameter(pv->v, "PrintingMode")) == 0)
3297	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(output_types[i].button),
3298				     TRUE);
3299    }
3300
3301  /*
3302   * Now get option parameters.
3303   */
3304
3305  update_options();
3306  do_color_updates ();
3307
3308  gtk_option_menu_set_history (GTK_OPTION_MENU (orientation_menu),
3309			       pv->orientation + 1);
3310
3311  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(units[pv->unit].checkbox),
3312			       TRUE);
3313  gtk_label_set_text(GTK_LABEL(units_label), units[pv->unit].name);
3314  suppress_preview_update--;
3315  preview_update ();
3316}
3317
3318static void
3319copy_count_callback(GtkAdjustment *adjustment, gpointer data)
3320{
3321  gint copy_count = (gint) adjustment->value;
3322  stpui_plist_set_copy_count(pv, copy_count);
3323  update_standard_print_command();
3324}
3325
3326static void
3327auto_paper_size_callback(GtkWidget *widget, gpointer data)
3328{
3329  auto_paper_size =
3330    gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(auto_paper_size_button));
3331  pv->auto_size_roll_feed_paper = auto_paper_size;
3332  set_orientation(pv->orientation);
3333  do_all_updates();
3334}
3335
3336static void
3337setup_auto_paper_size(void)
3338{
3339  const stp_papersize_t *ps =
3340    stp_get_papersize_by_name(stp_get_string_parameter(pv->v, "PageSize"));
3341  if (ps->height == 0 && ps->width != 0)		/* Implies roll feed */
3342    {
3343      g_signal_handlers_block_matched (G_OBJECT(auto_paper_size_button),
3344				       G_SIGNAL_MATCH_DATA,
3345				       0,
3346				       0,
3347				       NULL,
3348				       NULL,
3349                                       NULL);
3350
3351      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(auto_paper_size_button),
3352				   pv->auto_size_roll_feed_paper);
3353      gtk_widget_show(auto_paper_size_button);
3354      g_signal_handlers_unblock_matched (G_OBJECT(auto_paper_size_button),
3355					 G_SIGNAL_MATCH_DATA,
3356					 0,
3357					 0,
3358					 NULL,
3359					 NULL,
3360					 NULL);
3361    }
3362  else
3363    {
3364      gtk_widget_hide(auto_paper_size_button);
3365      auto_paper_size = 0;
3366    }
3367}
3368
3369static void
3370queue_callback (GtkWidget *widget,
3371		gpointer   data)
3372{
3373  int i;
3374  int count = stp_string_list_count(stpui_system_print_queues);
3375  const gchar *result =
3376    gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(queue_combo)->entry));
3377  for (i = 0; i < count; i++)
3378    {
3379      const stp_param_string_t *s =
3380	stp_string_list_param(stpui_system_print_queues, i);
3381      if (!strcmp(result, s->text))
3382	{
3383	  stpui_plist_set_queue_name(pv, s->name);
3384	  do_all_updates();
3385	  return;
3386	}
3387    }
3388}
3389
3390static void
3391setup_callback (GtkWidget *widget)
3392{
3393  const gchar *new_value = gtk_entry_get_text (GTK_ENTRY (widget));
3394
3395  if (widget == custom_command_entry)
3396    stpui_plist_set_custom_command(pv, new_value);
3397  else if (widget == file_entry)
3398    {
3399      stpui_plist_set_output_filename(pv, new_value);
3400      gtk_file_selection_set_filename
3401	(GTK_FILE_SELECTION (file_browser),
3402	 gtk_entry_get_text (GTK_ENTRY (file_entry)));
3403    }
3404}
3405
3406/*
3407 *  plist_callback() - Update the current system printer.
3408 */
3409static void
3410plist_callback (GtkWidget *widget,
3411		gpointer   data)
3412{
3413  gint         i;
3414  char *tmp;
3415
3416  suppress_preview_update++;
3417  invalidate_frame ();
3418  invalidate_preview_thumbnail ();
3419  reset_preview ();
3420
3421  if (widget)
3422    {
3423      const gchar *result =
3424	gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(printer_combo)->entry));
3425
3426      for (i = 0; i < stpui_plist_count; i++)
3427	{
3428	  if (! strcmp (result, stp_string_list_param(printer_list, i)->text))
3429	    {
3430	      stpui_plist_current = i;
3431	      break;
3432	    }
3433	}
3434    }
3435  else
3436    {
3437      stpui_plist_current = (gint) data;
3438    }
3439
3440  set_current_printer();
3441  build_queue_combo();
3442  manufacturer = stp_printer_get_manufacturer(stp_get_printer(pv->v));
3443  build_printer_driver_clist();
3444
3445  if (strcmp(stp_get_driver(pv->v), "") != 0)
3446    tmp_printer = stp_get_printer(pv->v);
3447
3448  gtk_entry_set_text(GTK_ENTRY(file_entry),
3449		     stpui_plist_get_output_filename(pv));
3450  tmp = stpui_build_standard_print_command(pv, stp_get_printer(pv->v));
3451  gtk_entry_set_text(GTK_ENTRY(standard_cmd_entry), tmp);
3452  stp_free(tmp);
3453  gtk_entry_set_text(GTK_ENTRY(custom_command_entry),
3454		     stpui_plist_get_custom_command(pv));
3455  gtk_spin_button_set_value(GTK_SPIN_BUTTON(copy_count_spin_button),
3456			    (gfloat) stpui_plist_get_copy_count(pv));
3457  do_all_updates();
3458
3459  setup_update ();
3460  do_all_updates();
3461  suppress_preview_update--;
3462  update_adjusted_thumbnail(TRUE);
3463  preview_update ();
3464}
3465
3466static void
3467show_all_paper_sizes_callback(GtkWidget *widget, gpointer data)
3468{
3469  int i;
3470  stpui_show_all_paper_sizes =
3471    gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
3472  for (i = 0; i < current_option_count; i++)
3473    {
3474      option_t *option = &(current_options[i]);
3475      if (option->fast_desc &&
3476	  strcmp(option->fast_desc->name, "PageSize") == 0)
3477	{
3478	  build_a_combo(option);
3479	  break;
3480	}
3481    }
3482}
3483
3484static void
3485custom_media_size_callback(GtkWidget *widget,
3486			   gpointer data)
3487{
3488  gint width_limit, height_limit;
3489  gint min_width_limit, min_height_limit;
3490  gdouble new_printed_value = atof(gtk_entry_get_text(GTK_ENTRY(widget)));
3491  gint new_value = SCALE(new_printed_value, units[pv->unit].scale);
3492  invalidate_frame ();
3493  invalidate_preview_thumbnail ();
3494  reset_preview ();
3495
3496  stp_get_size_limit(pv->v, &width_limit, &height_limit,
3497		     &min_width_limit, &min_height_limit);
3498  if (widget == custom_size_width)
3499    {
3500      if (new_value < min_width_limit)
3501	new_value = min_width_limit;
3502      else if (new_value > width_limit)
3503	new_value = width_limit;
3504      stp_set_page_width (pv->v, new_value);
3505    }
3506  else
3507    {
3508      if (new_value < min_height_limit)
3509	new_value = min_height_limit;
3510      else if (new_value > height_limit)
3511	new_value = height_limit;
3512      stp_set_page_height (pv->v, new_value);
3513    }
3514  set_entry_value (widget, new_value, 0);
3515  preview_update ();
3516}
3517
3518
3519/*
3520 *  media_size_callback() - Update the current media size.
3521 */
3522static void
3523set_media_size(const gchar *new_media_size)
3524{
3525  static int setting_media_size = 0;
3526  const stp_papersize_t *pap = stp_get_papersize_by_name (new_media_size);
3527
3528  if (setting_media_size)
3529    return;
3530  setting_media_size++;
3531
3532  if (pap)
3533    {
3534      gint size;
3535      int old_width = stp_get_page_width(pv->v);
3536      int old_height = stp_get_page_height(pv->v);
3537      int need_preview_update = 0;
3538
3539      if (! stpui_show_all_paper_sizes &&
3540	  (pap->paper_unit == PAPERSIZE_METRIC_EXTENDED ||
3541	   pap->paper_unit == PAPERSIZE_ENGLISH_EXTENDED))
3542	{
3543	  int i;
3544	  stp_parameter_t desc;
3545	  stp_describe_parameter(pv->v, "PageSize", &desc);
3546	  stp_set_string_parameter(pv->v, "PageSize", desc.deflt.str);
3547	  pap = stp_get_papersize_by_name(desc.deflt.str);
3548	  stp_parameter_description_destroy(&desc);
3549	  for (i = 0; i < current_option_count; i++)
3550	    {
3551	      option_t *option = &(current_options[i]);
3552	      if (option->fast_desc &&
3553		  strcmp(option->fast_desc->name, "PageSize") == 0)
3554		{
3555		  build_a_combo(option);
3556		  break;
3557		}
3558	    }
3559	}
3560
3561      if (pap->width == 0)
3562	{
3563	  int max_w, max_h, min_w, min_h;
3564	  stp_get_size_limit(pv->v, &max_w, &max_h, &min_w, &min_h);
3565	  size = old_width;
3566	  if (size < min_w)
3567	    size = min_w;
3568	  else if (size > max_w)
3569	    size = max_w;
3570	  gtk_widget_set_sensitive (GTK_WIDGET (custom_size_width), TRUE);
3571	  gtk_entry_set_editable (GTK_ENTRY (custom_size_width), TRUE);
3572	}
3573      else
3574	{
3575	  size = pap->width;
3576	  gtk_widget_set_sensitive (GTK_WIDGET (custom_size_width), FALSE);
3577	  gtk_entry_set_editable (GTK_ENTRY (custom_size_width), FALSE);
3578	}
3579      if (size != old_width)
3580	{
3581	  need_preview_update = 1;
3582	  set_entry_value (custom_size_width, size, 0);
3583	  stp_set_page_width (pv->v, size);
3584	}
3585
3586      setup_auto_paper_size();
3587      if (pap->height == 0)
3588	{
3589	  int max_w, max_h, min_w, min_h;
3590	  stp_get_size_limit(pv->v, &max_w, &max_h, &min_w, &min_h);
3591	  if (auto_paper_size)
3592	    {
3593	      int l, r, b, t;
3594	      stp_set_page_height(pv->v, 0);
3595	      old_height = 0;
3596	      stp_get_imageable_area(pv->v, &l, &r, &b, &t);
3597	      gtk_widget_set_sensitive(GTK_WIDGET(custom_size_height), FALSE);
3598	      gtk_entry_set_editable(GTK_ENTRY(custom_size_height), FALSE);
3599	      size = print_height;
3600	    }
3601	  else
3602	    {
3603	      gtk_widget_set_sensitive (GTK_WIDGET (custom_size_height), TRUE);
3604	      gtk_entry_set_editable (GTK_ENTRY (custom_size_height), TRUE);
3605	      size = old_height;
3606	    }
3607	  if (size < min_h)
3608	    size = min_h;
3609	  else if (size > max_h)
3610	    size = max_h;
3611	}
3612      else
3613	{
3614	  size = pap->height;
3615	  gtk_widget_set_sensitive(GTK_WIDGET (custom_size_height), FALSE);
3616	  gtk_entry_set_editable (GTK_ENTRY (custom_size_height), FALSE);
3617	}
3618      if (size != old_height)
3619	{
3620	  need_preview_update = 1;
3621	  set_entry_value (custom_size_height, size, 0);
3622	  stp_set_page_height (pv->v, size);
3623	}
3624      if (need_preview_update)
3625	{
3626	  invalidate_preview_thumbnail();
3627	  invalidate_frame();
3628	  preview_update();
3629	}
3630    }
3631  setting_media_size--;
3632}
3633
3634static gboolean
3635refresh_all_options(gpointer data)
3636{
3637  do_all_updates();
3638  do_all_updates();		/* Update twice to pick up cascading changes */
3639  return FALSE;
3640}
3641
3642static void
3643combo_callback(GtkWidget *widget, gpointer data)
3644{
3645  option_t *option = (option_t *)data;
3646  const gchar *new_value =
3647    stpui_combo_get_name(option->info.list.combo, option->info.list.params);
3648  const gchar *value =
3649    stp_get_string_parameter(pv->v, option->fast_desc->name);
3650  if (value && new_value)
3651    {
3652      reset_preview();
3653      if (!value || strcmp(value, new_value) != 0)
3654	{
3655	  invalidate_frame();
3656	  invalidate_preview_thumbnail();
3657	  stp_set_string_parameter(pv->v, option->fast_desc->name, new_value);
3658	  if (strcmp(option->fast_desc->name, "PageSize") == 0)
3659	    set_media_size(new_value);
3660	  g_idle_add(refresh_all_options, NULL);
3661	  if (option->fast_desc->p_class == STP_PARAMETER_CLASS_OUTPUT)
3662	    update_adjusted_thumbnail(TRUE);
3663	  preview_update();
3664	}
3665    }
3666}
3667
3668/*
3669 *  orientation_callback() - Update the current media size.
3670 */
3671static void
3672orientation_callback (GtkWidget *widget,
3673		      gpointer   data)
3674{
3675  reset_preview ();
3676
3677  if (pv->orientation != (gint) data)
3678    {
3679      invalidate_preview_thumbnail ();
3680      set_orientation((gint) data);
3681      update_adjusted_thumbnail(TRUE);
3682      preview_update ();
3683    }
3684}
3685
3686/*
3687 *  output_type_callback() - Update the current output type.
3688 */
3689static void
3690output_type_callback (GtkWidget *widget,
3691		      gpointer   data)
3692{
3693  reset_preview ();
3694
3695  if (GTK_TOGGLE_BUTTON (widget)->active)
3696    {
3697      if (strcmp((const char *) data, "BW") == 0)
3698	gtk_widget_hide(output_color_vbox);
3699      else
3700	gtk_widget_show(output_color_vbox);
3701      stp_set_string_parameter(pv->v, "PrintingMode", (const char *) data);
3702      invalidate_preview_thumbnail ();
3703      update_adjusted_thumbnail (TRUE);
3704      set_options_active(NULL);
3705      preview_update ();
3706      do_all_updates();
3707    }
3708}
3709
3710static void
3711command_type_callback(GtkWidget *widget, gpointer data)
3712{
3713  if (strcmp((const char *) data, "Standard") == 0)
3714    {
3715      gtk_widget_set_sensitive(standard_cmd_entry, TRUE);
3716      gtk_widget_set_sensitive(queue_combo, TRUE);
3717      gtk_widget_set_sensitive(file_entry, FALSE);
3718      gtk_entry_set_editable(GTK_ENTRY(file_entry), FALSE);
3719      gtk_widget_set_sensitive(custom_command_entry, FALSE);
3720      gtk_entry_set_editable(GTK_ENTRY(custom_command_entry), FALSE);
3721      gtk_widget_hide(GTK_WIDGET(file_browser));
3722      gtk_widget_set_sensitive(file_button, FALSE);
3723      gtk_widget_set_sensitive(copy_count_spin_button, TRUE);
3724      stpui_plist_set_command_type(pv, COMMAND_TYPE_DEFAULT);
3725    }
3726  else if (strcmp((const char *) data, "Custom") == 0)
3727    {
3728      gtk_widget_set_sensitive(standard_cmd_entry, FALSE);
3729      gtk_widget_set_sensitive(queue_combo, FALSE);
3730      gtk_widget_set_sensitive(file_entry, FALSE);
3731      gtk_entry_set_editable(GTK_ENTRY(file_entry), FALSE);
3732      gtk_widget_set_sensitive(custom_command_entry, TRUE);
3733      gtk_entry_set_editable(GTK_ENTRY(custom_command_entry), TRUE);
3734      gtk_widget_hide(GTK_WIDGET(file_browser));
3735      gtk_widget_set_sensitive(file_button, FALSE);
3736      gtk_widget_set_sensitive(copy_count_spin_button, FALSE);
3737      stpui_plist_set_command_type(pv, COMMAND_TYPE_CUSTOM);
3738    }
3739  else if (strcmp((const char *) data, "File") == 0)
3740    {
3741      gtk_widget_set_sensitive(standard_cmd_entry, FALSE);
3742      gtk_widget_set_sensitive(queue_combo, FALSE);
3743      gtk_widget_set_sensitive(file_entry, TRUE);
3744      gtk_entry_set_editable(GTK_ENTRY(file_entry), TRUE);
3745      gtk_widget_set_sensitive(custom_command_entry, FALSE);
3746      gtk_entry_set_editable(GTK_ENTRY(custom_command_entry), FALSE);
3747      gtk_widget_set_sensitive(file_button, TRUE);
3748      gtk_widget_set_sensitive(copy_count_spin_button, FALSE);
3749      stpui_plist_set_command_type(pv, COMMAND_TYPE_FILE);
3750    }
3751}
3752
3753static void
3754set_all_entry_values(void)
3755{
3756  set_entry_value (top_entry, (stp_get_top (pv->v)), 1);
3757  set_entry_value (left_entry, (stp_get_left (pv->v)), 1);
3758/*
3759  set_entry_value (bottom_entry, (top + stp_get_top(pv->v) + print_height), 1);
3760*/
3761  set_entry_value (bottom_border_entry,
3762                   (paper_height - (stp_get_top (pv->v) + print_height)), 1);
3763/*
3764  set_entry_value (right_entry, (stp_get_left(pv->v) + print_width), 1);
3765*/
3766  set_entry_value (right_border_entry,
3767                   (paper_width - (stp_get_left (pv->v) + print_width)), 1);
3768  set_entry_value (width_entry, print_width, 1);
3769  set_entry_value (height_entry, print_height, 1);
3770  set_entry_value (custom_size_width, stp_get_page_width (pv->v), 1);
3771  set_entry_value (custom_size_height, stp_get_page_height (pv->v), 1);
3772}
3773
3774/*
3775 *  unit_callback() - Update the current unit.
3776 */
3777static void
3778unit_callback (GtkWidget *widget,
3779	       gpointer   data)
3780{
3781  reset_preview ();
3782
3783  if (GTK_TOGGLE_BUTTON (widget)->active)
3784    {
3785      pv->unit = (gint) data;
3786      gtk_label_set_text(GTK_LABEL(units_label), units[pv->unit].name);
3787      set_all_entry_values();
3788      update_options();
3789      do_color_updates();
3790    }
3791}
3792
3793static void
3794destroy_dialogs (void)
3795{
3796  int i;
3797  gtk_widget_destroy (color_adjust_dialog);
3798  gtk_widget_destroy (setup_dialog);
3799  gtk_widget_destroy (print_dialog);
3800  gtk_widget_destroy (new_printer_dialog);
3801  gtk_widget_destroy (about_dialog);
3802  for (i = 0; i < current_option_count; i++)
3803    {
3804      if (current_options[i].fast_desc->p_type == STP_PARAMETER_TYPE_CURVE &&
3805	  current_options[i].info.curve.dialog)
3806	gtk_widget_destroy(current_options[i].info.curve.dialog);
3807    }
3808}
3809
3810static void
3811dialogs_set_sensitive (gboolean sensitive)
3812{
3813  int i;
3814  gtk_widget_set_sensitive (color_adjust_dialog, sensitive);
3815  gtk_widget_set_sensitive (setup_dialog, sensitive);
3816  gtk_widget_set_sensitive (print_dialog, sensitive);
3817  gtk_widget_set_sensitive (new_printer_dialog, sensitive);
3818  gtk_widget_set_sensitive (about_dialog, sensitive);
3819  for (i = 0; i < current_option_count; i++)
3820    {
3821      if (current_options[i].fast_desc->p_type == STP_PARAMETER_TYPE_CURVE &&
3822	  current_options[i].info.curve.dialog)
3823	gtk_widget_set_sensitive(current_options[i].info.curve.dialog,
3824				 sensitive);
3825    }
3826}
3827
3828/*
3829 * 'print_callback()' - Start the print.
3830 */
3831static void
3832print_callback (void)
3833{
3834  if (stpui_plist_get_command_type(pv) == COMMAND_TYPE_FILE &&
3835      strlen(stpui_plist_get_output_filename(pv)) == 0)
3836    {
3837      dialogs_set_sensitive (FALSE);
3838      exit_after_file_ok = 1;
3839      gtk_widget_show (file_browser);
3840    }
3841  else
3842    {
3843      runme = TRUE;
3844      destroy_dialogs ();
3845    }
3846}
3847
3848/*
3849 *  printandsave_callback() -
3850 */
3851static void
3852printandsave_callback (void)
3853{
3854  saveme = TRUE;
3855  print_callback();
3856}
3857
3858static void
3859about_callback (void)
3860{
3861  gtk_widget_show (about_dialog);
3862}
3863
3864/*
3865 *  save_callback() - save settings, don't destroy dialog
3866 */
3867static void
3868save_callback (void)
3869{
3870  reset_preview ();
3871  stpui_printrc_save ();
3872}
3873
3874/*
3875 *  setup_update() - update widgets in the setup dialog
3876 */
3877static void
3878setup_update (void)
3879{
3880  GtkAdjustment *adjustment;
3881  gint           idx = 0;
3882  gint i;
3883  gchar *tmp;
3884  stp_parameter_t desc;
3885  const char *ppd_file_name = stp_get_file_parameter(pv->v, "PPDFile");
3886
3887  for (i = 0; i < GTK_CLIST(manufacturer_clist)->rows; i++)
3888    {
3889      (void) gtk_clist_get_text(GTK_CLIST(manufacturer_clist), i, 0, &tmp);
3890      if (tmp && strcmp(manufacturer, tmp) == 0)
3891	{
3892	  idx = i;
3893	  break;
3894	}
3895    }
3896  gtk_clist_select_row(GTK_CLIST(manufacturer_clist), idx, 0);
3897
3898  idx = stp_get_printer_index_by_driver (stp_get_driver (pv->v));
3899
3900  idx = gtk_clist_find_row_from_data(GTK_CLIST(printer_driver),
3901				     (gpointer) idx);
3902/*
3903  if (idx >= 0)
3904    idx = 0;
3905*/
3906  gtk_clist_select_row (GTK_CLIST (printer_driver), idx, 0);
3907  stp_describe_parameter(pv->v, "ModelName", &desc);
3908  if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST && desc.is_active &&
3909      desc.deflt.str)
3910    {
3911      const char *extra_printer_model = desc.deflt.str;
3912      char *label_text =
3913	g_malloc(strlen(gettext (stp_printer_get_long_name (tmp_printer))) +
3914		 2 +		/* " (" */
3915		 strlen(extra_printer_model) +
3916		 2);		/* ")" + null terminator */
3917      strcpy(label_text, extra_printer_model);
3918      strcat(label_text, " (");
3919      strcat(label_text, gettext (stp_printer_get_long_name (tmp_printer)));
3920      strcat(label_text, ")");
3921      gtk_label_set_text (GTK_LABEL (printer_model_label), label_text);
3922      g_free(label_text);
3923    }
3924  else
3925    {
3926      gtk_label_set_text (GTK_LABEL (printer_model_label),
3927			  gettext (stp_printer_get_long_name (tmp_printer)));
3928    }
3929  stp_parameter_description_destroy(&desc);
3930
3931  if (ppd_file_name)
3932    gtk_entry_set_text (GTK_ENTRY (ppd_file), ppd_file_name);
3933  else
3934    gtk_entry_set_text (GTK_ENTRY (ppd_file), "");
3935  ppd_file_callback(ppd_file, NULL);
3936
3937  if (stp_parameter_find_in_settings(pv->v, "PPDFile"))
3938    {
3939      gtk_widget_show (ppd_box);
3940      gtk_widget_show (ppd_label);
3941      gtk_widget_show (ppd_model_label);
3942      gtk_widget_show (ppd_model);
3943    }
3944  else
3945    {
3946      gtk_widget_hide (ppd_box);
3947      gtk_widget_hide (ppd_label);
3948      gtk_widget_hide (ppd_model_label);
3949      gtk_widget_hide (ppd_model);
3950    }
3951  gtk_entry_set_text (GTK_ENTRY (custom_command_entry),
3952		      stpui_plist_get_custom_command (pv));
3953
3954  adjustment = GTK_CLIST (printer_driver)->vadjustment;
3955  gtk_adjustment_set_value
3956    (adjustment,
3957     adjustment->lower + idx * (adjustment->upper - adjustment->lower) /
3958     GTK_CLIST (printer_driver)->rows);
3959
3960  i = stpui_plist_get_command_type(pv);
3961  if (i >= 0 && i < command_options_count)
3962    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(command_options[i].button),
3963				 TRUE);
3964}
3965
3966static void
3967ppd_file_callback(GtkWidget *widget, gpointer data)
3968{
3969  const gchar *name = gtk_entry_get_text(GTK_ENTRY(widget));
3970  if (name && pv && pv->v)
3971    {
3972      stp_parameter_t desc;
3973      stp_vars_t *v = stp_vars_create_copy(pv->v);
3974      stp_set_file_parameter(v, "PPDFile", name);
3975      stp_describe_parameter(v, "ModelName", &desc);
3976      if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST && desc.is_active)
3977	gtk_label_set_text(GTK_LABEL(ppd_model), desc.deflt.str);
3978      else
3979	gtk_label_set_text(GTK_LABEL(ppd_model), "");
3980      stp_parameter_description_destroy(&desc);
3981      stp_vars_destroy(v);
3982    }
3983  else
3984    gtk_label_set_text(GTK_LABEL(ppd_model), "");
3985}
3986
3987/*
3988 *  setup_open_callback() -
3989 */
3990static void
3991setup_open_callback (void)
3992{
3993  static gboolean first_time = TRUE;
3994  manufacturer = stp_printer_get_manufacturer(stp_get_printer(pv->v));
3995  build_printer_driver_clist();
3996
3997  reset_preview ();
3998  setup_update ();
3999
4000/*  gtk_widget_set_sensitive(GTK_DIALOG(print_dialog)->action_area, FALSE); */
4001  gtk_widget_show (setup_dialog);
4002
4003  if (first_time)
4004    {
4005      /* Make sure the driver scroller gets positioned correctly. */
4006      setup_update ();
4007      first_time = FALSE;
4008    }
4009}
4010
4011/*
4012 *  new_printer_open_callback() -
4013 */
4014static void
4015new_printer_open_callback (void)
4016{
4017  reset_preview ();
4018  gtk_entry_set_text (GTK_ENTRY (new_printer_entry), "");
4019  gtk_widget_show (new_printer_dialog);
4020}
4021
4022static void
4023set_printer(void)
4024{
4025  manufacturer = stp_printer_get_manufacturer(tmp_printer);
4026  build_printer_driver_clist();
4027  build_queue_combo();
4028  stp_set_driver (pv->v, stp_printer_get_driver (tmp_printer));
4029  stpui_plist_set_custom_command
4030    (pv, gtk_entry_get_text (GTK_ENTRY (custom_command_entry)));
4031  stpui_plist_set_output_filename
4032    (pv, gtk_entry_get_text (GTK_ENTRY (file_entry)));
4033  stp_set_file_parameter (pv->v, "PPDFile",
4034			  gtk_entry_get_text (GTK_ENTRY (ppd_file)));
4035  gtk_label_set_text (GTK_LABEL (printer_model_label),
4036                      gettext (stp_printer_get_long_name (tmp_printer)));
4037
4038  plist_callback (NULL, (gpointer) stpui_plist_current);
4039}
4040
4041/*
4042 *  setup_ok_callback() -
4043 */
4044static void
4045setup_ok_callback (void)
4046{
4047  gtk_widget_hide(ppd_browser);
4048  gtk_widget_hide(file_browser);
4049  gtk_widget_hide(setup_dialog);
4050  set_printer();
4051  gtk_widget_set_sensitive(GTK_DIALOG(print_dialog)->action_area, TRUE);
4052}
4053
4054/*
4055 *  setup_cancel_callback() -
4056 */
4057static void
4058setup_cancel_callback (void)
4059{
4060  gtk_widget_hide(ppd_browser);
4061  gtk_widget_hide(file_browser);
4062  gtk_widget_hide(setup_dialog);
4063  manufacturer = stp_printer_get_manufacturer(stp_get_printer(pv->v));
4064  build_printer_driver_clist();
4065  setup_update();
4066  gtk_widget_set_sensitive(GTK_DIALOG(print_dialog)->action_area, TRUE);
4067}
4068
4069/*
4070 *  setup_ok_callback() -
4071 */
4072static void
4073new_printer_ok_callback (void)
4074{
4075  const gchar *data = gtk_entry_get_text (GTK_ENTRY (new_printer_entry));
4076  stpui_plist_t   key;
4077
4078  if (strlen(data))
4079    {
4080      memset(&key, 0, sizeof(key));
4081      stpui_printer_initialize (&key);
4082      stpui_plist_copy(&key, pv);
4083      stpui_plist_set_name(&key, data);
4084
4085      if (stpui_plist_add (&key, 1))
4086	{
4087	  stp_vars_destroy(key.v);
4088	  g_free(key.name);
4089	  stpui_plist_current = stpui_plist_count - 1;
4090	  set_current_printer();
4091	  build_printer_combo ();
4092	  set_printer();
4093	}
4094    }
4095
4096  gtk_widget_hide (new_printer_dialog);
4097}
4098
4099static void
4100pop_ppd_box(void)
4101{
4102  const stp_vars_t *v = stp_printer_get_defaults(tmp_printer);
4103  if (stp_parameter_find_in_settings(v, "PPDFile"))
4104    {
4105      gtk_widget_show (ppd_label);
4106      gtk_widget_show (ppd_box);
4107      gtk_widget_show (ppd_model_label);
4108      gtk_widget_show (ppd_model);
4109    }
4110  else
4111    {
4112      gtk_widget_hide (ppd_label);
4113      gtk_widget_hide (ppd_box);
4114      gtk_widget_hide (ppd_model_label);
4115      gtk_widget_hide (ppd_model);
4116    }
4117}
4118
4119static void
4120build_printer_driver_clist(void)
4121{
4122  int i;
4123  int current_idx = 0;
4124  gtk_clist_clear(GTK_CLIST(printer_driver));
4125  for (i = 0; i < stp_printer_model_count (); i ++)
4126    {
4127      const stp_printer_t *the_printer = stp_get_printer_by_index (i);
4128
4129      if (strcmp(manufacturer, stp_printer_get_manufacturer(the_printer)) == 0)
4130	{
4131	  gchar *tmp=g_strdup(gettext(stp_printer_get_long_name(the_printer)));
4132	  /*
4133	   * FIXME Somehow if the raw printer comes before any of the
4134	   * "real" printers in the list of printers created in module.c,
4135	   * this code barfs on any of those printers added later.  For
4136	   * example, try listing olympus_LTX_stpi_module_data after
4137	   * raw_LTX_stpi_module_data.
4138	   */
4139
4140	  gtk_clist_insert (GTK_CLIST (printer_driver), current_idx, &tmp);
4141	  gtk_clist_set_row_data (GTK_CLIST (printer_driver), current_idx,
4142				  (gpointer) i);
4143	  g_free(tmp);
4144	  current_idx++;
4145	}
4146    }
4147}
4148
4149static void
4150manufacturer_callback(GtkWidget      *widget, /* I - Driver list */
4151		      gint            row,
4152		      gint            column,
4153		      GdkEventButton *event,
4154		      gpointer        data)
4155{
4156  static int calling_manufacturer_callback = 0;
4157  gchar *text;
4158  if (calling_manufacturer_callback)
4159    return;
4160  calling_manufacturer_callback++;
4161  if (gtk_clist_get_text(GTK_CLIST(widget), row, column, &text))
4162    manufacturer = text;
4163  build_printer_driver_clist();
4164  setup_update();
4165  calling_manufacturer_callback--;
4166}
4167
4168/*
4169 *  print_driver_callback() - Update the current printer driver.
4170 */
4171static void
4172print_driver_callback (GtkWidget      *widget, /* I - Driver list */
4173		       gint            row,
4174		       gint            column,
4175		       GdkEventButton *event,
4176		       gpointer        data)   /* I - Data */
4177{
4178  char *tmp;
4179  static int calling_print_driver_callback = 0;
4180  if (calling_print_driver_callback)
4181    return;
4182  calling_print_driver_callback++;
4183  invalidate_frame ();
4184  invalidate_preview_thumbnail ();
4185  reset_preview ();
4186  data = gtk_clist_get_row_data (GTK_CLIST (widget), row);
4187  tmp_printer = stp_get_printer_by_index ((gint) data);
4188  tmp = stpui_build_standard_print_command(pv, tmp_printer);
4189  gtk_entry_set_text(GTK_ENTRY(standard_cmd_entry), tmp);
4190  g_free(tmp);
4191
4192  pop_ppd_box();
4193  calling_print_driver_callback--;
4194}
4195
4196/*
4197 *  ppd_browse_callback() -
4198 */
4199static void
4200ppd_browse_callback (void)
4201{
4202  reset_preview ();
4203  gtk_file_selection_set_filename (GTK_FILE_SELECTION (ppd_browser),
4204				   gtk_entry_get_text (GTK_ENTRY (ppd_file)));
4205  gtk_widget_show (ppd_browser);
4206}
4207
4208/*
4209 *  ppd_ok_callback() -
4210 */
4211static void
4212ppd_ok_callback (void)
4213{
4214  reset_preview ();
4215  gtk_widget_hide (ppd_browser);
4216  gtk_entry_set_text
4217    (GTK_ENTRY (ppd_file),
4218     gtk_file_selection_get_filename (GTK_FILE_SELECTION (ppd_browser)));
4219  ppd_file_callback(ppd_file, NULL);
4220  update_options();
4221}
4222
4223/*
4224 *  ppd_browse_callback() -
4225 */
4226static void
4227file_browse_callback (void)
4228{
4229  reset_preview ();
4230  gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_browser),
4231				   gtk_entry_get_text (GTK_ENTRY (file_entry)));
4232  gtk_widget_show (file_browser);
4233}
4234
4235/*
4236 *  file_ok_callback() - print to file and go away
4237 */
4238static void
4239file_ok_callback (void)
4240{
4241  const char *filename =
4242    gtk_file_selection_get_filename(GTK_FILE_SELECTION(file_browser));
4243  gtk_widget_hide (file_browser);
4244  gtk_entry_set_text(GTK_ENTRY(file_entry), filename);
4245  stpui_plist_set_output_filename(pv, filename);
4246  if (exit_after_file_ok)
4247    {
4248      runme = TRUE;
4249      destroy_dialogs ();
4250    }
4251}
4252
4253/*
4254 *  file_cancel_callback() -
4255 */
4256static void
4257file_cancel_callback (void)
4258{
4259  exit_after_file_ok = 0;
4260  gtk_widget_hide (file_browser);
4261  dialogs_set_sensitive (TRUE);
4262}
4263
4264static void
4265fill_buffer_writefunc(void *priv, const char *buffer, size_t bytes)
4266{
4267  int mask = 0;
4268  int i;
4269
4270  priv_t *p = (priv_t *) priv;
4271  unsigned char *where = p->base_addr + p->offset;
4272  const unsigned char *xbuffer = (const unsigned char *)buffer;
4273
4274  if (strcmp(p->output_type, "Whitescale") == 0)
4275    {
4276      memcpy(where, xbuffer, bytes);
4277      p->offset += bytes;
4278    }
4279  else if (strcmp(p->output_type, "Grayscale") == 0)
4280    {
4281      for (i = 0; i < bytes; i++)
4282	where[i] = ~xbuffer[i];
4283      p->offset += bytes;
4284    }
4285  else if (strcmp(p->output_type, "RGB") == 0)
4286    {
4287      int pixels = bytes / 3;
4288      if (bytes + p->offset > p->limit)
4289	bytes = p->limit - p->offset;
4290      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(red_button)))
4291	mask |= 1;
4292      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(green_button)))
4293	mask |= 2;
4294      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(blue_button)))
4295	mask |= 4;
4296
4297      memset(where, 0, pixels * 3);
4298      for (i = 0; i < pixels; i++)
4299	{
4300	  if (mask & 1)
4301	    where[0] = xbuffer[0];
4302	  if (mask & 2)
4303	    where[1] = xbuffer[1];
4304	  if (mask & 4)
4305	    where[2] = xbuffer[2];
4306	  where += 3;
4307	  xbuffer += 3;
4308	}
4309      p->offset += pixels * 3;
4310    }
4311  else if (strcmp(p->output_type, "CMY") == 0)
4312    {
4313      int pixels = bytes / 3;
4314      if (bytes + p->offset > p->limit)
4315	bytes = p->limit - p->offset;
4316      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cyan_button)))
4317	mask |= 1;
4318      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(magenta_button)))
4319	mask |= 2;
4320      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(yellow_button)))
4321	mask |= 4;
4322
4323      memset(where, 0xff, pixels * 3);
4324      for (i = 0; i < pixels; i++)
4325	{
4326	  if (mask & 1)
4327	    where[0] = ~xbuffer[0];
4328	  if (mask & 2)
4329	    where[1] = ~xbuffer[1];
4330	  if (mask & 4)
4331	    where[2] = ~xbuffer[2];
4332	  where += 3;
4333	  xbuffer += 3;
4334	}
4335      p->offset += pixels * 3;
4336    }
4337  else
4338    {
4339      int pixels = bytes / 4;
4340      if (bytes + p->offset > p->limit)
4341	bytes = p->limit - p->offset;
4342      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cyan_button)))
4343	mask |= 1;
4344      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(magenta_button)))
4345	mask |= 2;
4346      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(yellow_button)))
4347	mask |= 4;
4348      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(black_button)))
4349	mask |= 8;
4350
4351      memset(where, 0xff, pixels * 3);
4352      for (i = 0; i < pixels; i++)
4353	{
4354	  if (mask & 8)
4355	    {
4356	      where[0] -= xbuffer[3];
4357	      where[1] -= xbuffer[3];
4358	      where[2] -= xbuffer[3];
4359	    }
4360	  if (mask & 1)
4361	    {
4362	      if (where[0] < xbuffer[0])
4363		where[0] = 0;
4364	      else
4365		where[0] -= xbuffer[0];
4366	    }
4367	  if (mask & 2)
4368	    {
4369	      if (where[1] < xbuffer[1])
4370		where[1] = 0;
4371	      else
4372		where[1] -= xbuffer[1];
4373	    }
4374	  if (mask & 4)
4375	    {
4376	      if (where[2] < xbuffer[2])
4377		where[2] = 0;
4378	      else
4379		where[2] -= xbuffer[2];
4380	    }
4381	  where += 3;
4382	  xbuffer += 4;
4383	}
4384      p->offset += pixels * 3;
4385    }
4386}
4387
4388/*
4389 * update_adjusted_thumbnail()
4390 */
4391
4392static void
4393redraw_color_swatch (void)
4394{
4395  static GdkGC *gc = NULL;
4396  static GdkColormap *cmap;
4397
4398  if (adjusted_thumbnail_data && swatch && swatch->widget.window)
4399    {
4400      if (gc == NULL)
4401	{
4402	  gc = gdk_gc_new (swatch->widget.window);
4403	  cmap = gtk_widget_get_colormap (GTK_WIDGET(swatch));
4404	}
4405
4406      if (!print_mode_is_color(pv->v))
4407	gdk_draw_gray_image(swatch->widget.window, gc, 0, 0,
4408			    thumbnail_w, thumbnail_h, GDK_RGB_DITHER_NORMAL,
4409			    adjusted_thumbnail_data, thumbnail_w);
4410      else
4411	gdk_draw_rgb_image(swatch->widget.window, gc, 0, 0,
4412			   thumbnail_w, thumbnail_h, GDK_RGB_DITHER_NORMAL,
4413			   adjusted_thumbnail_data, 3 * thumbnail_w);
4414    }
4415}
4416
4417static void
4418initialize_thumbnail(void)
4419{
4420  int i;
4421  if (stpui_get_thumbnail_func())
4422    {
4423      const guchar *internal_thumbnail_data;
4424      /*
4425       * Fetch a thumbnail of the image we're to print from the Gimp.
4426       */
4427
4428      thumbnail_w = thumbnail_hintw;
4429      thumbnail_h = thumbnail_hinth;
4430      internal_thumbnail_data =
4431	(stpui_get_thumbnail_func()) (stpui_get_thumbnail_data(), &thumbnail_w,
4432				      &thumbnail_h, &thumbnail_bpp, 0);
4433      if (adjusted_thumbnail_data)
4434	g_free(adjusted_thumbnail_data);
4435      if (preview_thumbnail_data)
4436	g_free(preview_thumbnail_data);
4437      if (thumbnail_data)
4438	g_free(thumbnail_data);
4439
4440      if (internal_thumbnail_data)
4441	{
4442	  /*
4443	   * thumbnail_w and thumbnail_h have now been adjusted to the actual
4444	   * thumbnail dimensions.  Now initialize a color-adjusted version of
4445	   * the thumbnail.
4446	   */
4447
4448	  adjusted_thumbnail_data = g_malloc (3 * thumbnail_w * thumbnail_h);
4449	  preview_thumbnail_data = g_malloc (3 * thumbnail_w * thumbnail_h);
4450	  thumbnail_data = g_malloc (3 * thumbnail_w * thumbnail_h);
4451
4452	  switch (thumbnail_bpp)
4453	    {
4454	    case 1:
4455	      for (i = 0; i < thumbnail_w * thumbnail_h; i++)
4456		{
4457		  gint val = internal_thumbnail_data[i];
4458		  thumbnail_data[(3 * i) + 0] = val;
4459		  thumbnail_data[(3 * i) + 1] = val;
4460		  thumbnail_data[(3 * i) + 2] = val;
4461		}
4462	      break;
4463	    case 3:
4464	      memcpy(thumbnail_data, internal_thumbnail_data,
4465		     3 * thumbnail_w * thumbnail_h);
4466	      break;
4467	    case 2:
4468	      for (i = 0; i < thumbnail_w * thumbnail_h; i++)
4469		{
4470		  gint val = internal_thumbnail_data[2 * i];
4471		  gint alpha = internal_thumbnail_data[(2 * i) + 1];
4472		  thumbnail_data[(3 * i) +0] = val * alpha / 255 + 255 - alpha;
4473		  thumbnail_data[(3 * i) +1] = val * alpha / 255 + 255 - alpha;
4474		  thumbnail_data[(3 * i) +2] = val * alpha / 255 + 255 - alpha;
4475		}
4476	      break;
4477	    case 4:
4478	      for (i = 0; i < thumbnail_w * thumbnail_h; i++)
4479		{
4480		  gint r = internal_thumbnail_data[(4 * i)];
4481		  gint g = internal_thumbnail_data[(4 * i) + 1];
4482		  gint b = internal_thumbnail_data[(4 * i) + 2];
4483		  gint alpha = internal_thumbnail_data[(4 * i) + 3];
4484		  thumbnail_data[(3 * i) + 0] = r * alpha / 255 + 255 - alpha;
4485		  thumbnail_data[(3 * i) + 1] = g * alpha / 255 + 255 - alpha;
4486		  thumbnail_data[(3 * i) + 2] = b * alpha / 255 + 255 - alpha;
4487		}
4488	      break;
4489	    default:
4490	      break;
4491	      /* Whatever */
4492	    }
4493	  thumbnail_bpp = 3;
4494	}
4495      else
4496	{
4497	  thumbnail_h = 0;
4498	  thumbnail_w = 0;
4499	}
4500    }
4501  else
4502    {
4503      thumbnail_h = 0;
4504      thumbnail_w = 0;
4505    }
4506}
4507
4508static int
4509compute_thumbnail(const stp_vars_t *v)
4510{
4511  priv_t priv;
4512  int answer = 1;
4513  stp_image_t *im = stpui_image_thumbnail_new(thumbnail_data, thumbnail_w,
4514					      thumbnail_h, thumbnail_bpp);
4515  stp_vars_t *nv = stp_vars_create_copy(v);
4516  const char *output_type = stp_describe_output(nv);
4517  stp_set_top(nv, 0);
4518  stp_set_left(nv, 0);
4519  stp_set_width(nv, thumbnail_w);
4520  stp_set_height(nv, thumbnail_h);
4521  stp_set_outfunc(nv, fill_buffer_writefunc);
4522  stp_set_outdata(nv, &priv);
4523  stp_set_errfunc(nv, stpui_get_errfunc());
4524  stp_set_errdata(nv, stpui_get_errdata());
4525  if (strcmp(output_type, "Whitescale") == 0)
4526    {
4527      gtk_widget_hide(output_color_vbox);
4528      priv.bpp = 1;
4529      priv.output_type = "Whitescale";
4530      stp_set_string_parameter(nv, "InkType", "RGBGray");
4531    }
4532  else if (strcmp(output_type, "Grayscale") == 0)
4533    {
4534      gtk_widget_hide(output_color_vbox);
4535      priv.bpp = 1;
4536      priv.output_type = "Grayscale";
4537      stp_set_string_parameter(nv, "InkType", "CMYGray");
4538    }
4539  else if (strcmp(output_type, "CMY") == 0)
4540    {
4541      gtk_widget_hide(black_button);
4542      gtk_widget_hide(red_button);
4543      gtk_widget_hide(green_button);
4544      gtk_widget_hide(blue_button);
4545      gtk_widget_show(cyan_button);
4546      gtk_widget_show(magenta_button);
4547      gtk_widget_show(yellow_button);
4548      gtk_widget_show(output_color_vbox);
4549      priv.bpp = 3;
4550      priv.output_type = "CMY";
4551      stp_set_string_parameter(nv, "InkType", "CMY");
4552    }
4553  else if (strcmp(output_type, "RGB") == 0)
4554    {
4555      gtk_widget_hide(cyan_button);
4556      gtk_widget_hide(magenta_button);
4557      gtk_widget_hide(yellow_button);
4558      gtk_widget_hide(black_button);
4559      gtk_widget_show(red_button);
4560      gtk_widget_show(green_button);
4561      gtk_widget_show(blue_button);
4562      gtk_widget_show(output_color_vbox);
4563      priv.bpp = 3;
4564      priv.output_type = "RGB";
4565      stp_set_string_parameter(nv, "InkType", "RGB");
4566    }
4567  else
4568    {
4569      gtk_widget_hide(red_button);
4570      gtk_widget_hide(green_button);
4571      gtk_widget_hide(blue_button);
4572      gtk_widget_show(cyan_button);
4573      gtk_widget_show(magenta_button);
4574      gtk_widget_show(yellow_button);
4575      gtk_widget_show(black_button);
4576      gtk_widget_show(output_color_vbox);
4577      priv.bpp = 4;
4578      priv.output_type = "CMYK";
4579      stp_set_string_parameter(nv, "InkType", "CMYK");
4580    }
4581  stp_set_page_height(nv, thumbnail_h);
4582  stp_set_page_width(nv, thumbnail_w);
4583  stp_set_driver(nv, "raw-data-8");
4584  stp_set_float_parameter(nv, "Density", 1.0);
4585  stp_set_float_parameter(nv, "InkLimit", 0);
4586  stp_set_string_parameter(nv, "InputImageType", "RGB");
4587  stp_clear_file_parameter(nv, "LUTDumpFile");
4588
4589  priv.base_addr = adjusted_thumbnail_data;
4590  priv.offset = 0;
4591  priv.limit = thumbnail_bpp * thumbnail_h * thumbnail_w;
4592
4593  if (stp_verify(nv) != 1 || stp_print(nv, im) != 1)
4594    {
4595      answer = 0;
4596      fprintf(stderr, "Could not print thumbnail!\n");
4597    }
4598  stp_vars_destroy(nv);
4599  thumbnail_needs_rebuild = FALSE;
4600  return answer;
4601}
4602
4603static void
4604set_thumbnail_orientation(void)
4605{
4606  gint           x, y;
4607  gint preview_limit = (thumbnail_h * thumbnail_w) - 1;
4608  gint bpp;
4609  if (!print_mode_is_color(pv->v))
4610    bpp = 1;
4611  else
4612    bpp = 3;
4613  switch (physical_orientation)
4614    {
4615    case ORIENT_PORTRAIT:
4616      memcpy(preview_thumbnail_data, adjusted_thumbnail_data,
4617	     bpp * thumbnail_h * thumbnail_w);
4618      break;
4619    case ORIENT_SEASCAPE:
4620      for (x = 0; x < thumbnail_w; x++)
4621	for (y = 0; y < thumbnail_h; y++)
4622	  memcpy((preview_thumbnail_data +
4623		  bpp * (preview_limit - (x * thumbnail_h + y))),
4624		 (adjusted_thumbnail_data +
4625		  bpp * ((thumbnail_h - y - 1) * thumbnail_w + x)), bpp);
4626      break;
4627
4628    case ORIENT_UPSIDEDOWN:
4629      for (x = 0; x < thumbnail_h * thumbnail_w; x++)
4630	memcpy((preview_thumbnail_data + bpp * (preview_limit - x)),
4631	       adjusted_thumbnail_data + bpp * x, bpp);
4632      break;
4633    case ORIENT_LANDSCAPE:
4634      for (x = 0; x < thumbnail_w; x++)
4635	for (y = 0; y < thumbnail_h; y++)
4636	  memcpy((preview_thumbnail_data + bpp * (x * thumbnail_h + y)),
4637		 (adjusted_thumbnail_data +
4638		  bpp * ((thumbnail_h - y - 1) * thumbnail_w + x)), bpp);
4639      break;
4640    }
4641}
4642
4643static void
4644draw_arrow (GdkWindow *w,
4645            GdkGC     *gc,
4646            gint       paper_left,
4647            gint       paper_top)
4648{
4649  gint u  = preview_ppi/2;
4650  gint ox = paper_left + preview_ppi * paper_width / INCH / 2;
4651  gint oy = paper_top + preview_ppi * paper_height / INCH / 2;
4652
4653  oy -= preview_ppi * paper_height / INCH / 4;
4654  if (oy < paper_top + u)
4655    oy = paper_top + u;
4656  gdk_draw_line (w, gc, ox, oy - u, ox - u, oy);
4657  gdk_draw_line (w, gc, ox, oy - u, ox + u, oy);
4658  gdk_draw_line (w, gc, ox, oy - u, ox, oy + u);
4659}
4660
4661static void
4662create_valid_preview(guchar **preview_data)
4663{
4664  if (adjusted_thumbnail_data)
4665    {
4666      gint bpp = (print_mode_is_color(pv->v)) ? 3 : 1;
4667      gint v_denominator = preview_h > 1 ? preview_h - 1 : 1;
4668      gint v_numerator = (preview_thumbnail_h - 1) % v_denominator;
4669      gint v_whole = (preview_thumbnail_h - 1) / v_denominator;
4670      gint h_denominator = preview_w > 1 ? preview_w - 1 : 1;
4671      gint h_numerator = (preview_thumbnail_w - 1) % h_denominator;
4672      gint h_whole = (preview_thumbnail_w - 1) / h_denominator;
4673      gint adjusted_preview_width = bpp * preview_w;
4674      gint adjusted_thumbnail_width = bpp * preview_thumbnail_w;
4675      gint v_cur = 0;
4676      gint v_last = -1;
4677      gint v_error = v_denominator / 2;
4678      gint y;
4679      gint i;
4680
4681      if (*preview_data)
4682	g_free (*preview_data);
4683      *preview_data = g_malloc (bpp * preview_h * preview_w);
4684
4685      for (y = 0; y < preview_h; y++)
4686	{
4687	  guchar *outbuf = *preview_data + adjusted_preview_width * y;
4688
4689	  if (v_cur == v_last)
4690	    memcpy (outbuf, outbuf-adjusted_preview_width,
4691		    adjusted_preview_width);
4692	  else
4693	    {
4694	      guchar *inbuf = preview_thumbnail_data - bpp
4695		+ adjusted_thumbnail_width * v_cur;
4696
4697	      gint h_cur = 0;
4698	      gint h_last = -1;
4699	      gint h_error = h_denominator / 2;
4700	      gint x;
4701
4702	      v_last = v_cur;
4703	      for (x = 0; x < preview_w; x++)
4704		{
4705		  if (h_cur == h_last)
4706		    {
4707		      for (i = 0; i < bpp; i++)
4708			outbuf[i] = outbuf[i - bpp];
4709		    }
4710		  else
4711		    {
4712		      inbuf += bpp * (h_cur - h_last);
4713		      h_last = h_cur;
4714		      for (i = 0; i < bpp; i++)
4715			outbuf[i] = inbuf[i];
4716		    }
4717		  outbuf += bpp;
4718		  h_cur += h_whole;
4719		  h_error += h_numerator;
4720		  if (h_error >= h_denominator)
4721		    {
4722		      h_error -= h_denominator;
4723		      h_cur++;
4724		    }
4725		}
4726	    }
4727	  v_cur += v_whole;
4728	  v_error += v_numerator;
4729	  if (v_error >= v_denominator)
4730	    {
4731	      v_error -= v_denominator;
4732	      v_cur++;
4733	    }
4734	}
4735      preview_valid = TRUE;
4736    }
4737}
4738
4739/*
4740 *  preview_update_callback() -
4741 */
4742static void
4743do_preview_thumbnail (void)
4744{
4745  static GdkGC	*gc    = NULL;
4746  static GdkGC  *gcinv = NULL;
4747  static GdkGC  *gcset = NULL;
4748  static guchar *preview_data = NULL;
4749  gint    opx = preview_x;
4750  gint    opy = preview_y;
4751  gint    oph = preview_h;
4752  gint    opw = preview_w;
4753  gint paper_display_left, paper_display_top;
4754  gint printable_display_left, printable_display_top;
4755  gint paper_display_width, paper_display_height;
4756  gint printable_display_width, printable_display_height;
4757  int l_bottom = stp_get_top(pv->v) + stp_get_height(pv->v);
4758  int l_right = stp_get_left(pv->v) + stp_get_width(pv->v);
4759
4760  preview_ppi = preview_size_horiz * FINCH / (gdouble) paper_width;
4761
4762  if (preview_ppi > preview_size_vert * FINCH / (gdouble) paper_height)
4763    preview_ppi = preview_size_vert * FINCH / (gdouble) paper_height;
4764  if (preview_ppi > MAX_PREVIEW_PPI)
4765    preview_ppi = MAX_PREVIEW_PPI;
4766
4767  if (preview == NULL || preview->widget.window == NULL)
4768    return;
4769  /*
4770   * Center the page on the preview
4771   */
4772  paper_display_width = MAX(3, ROUNDUP(preview_ppi * paper_width, INCH));
4773  paper_display_height = MAX(3, ROUNDUP(preview_ppi * paper_height, INCH));
4774
4775  paper_display_left = (preview_size_horiz - paper_display_width) / 2;
4776  paper_display_top = (preview_size_vert - paper_display_height) / 2;
4777
4778  printable_display_width =
4779    MAX(3, ROUNDUP(preview_ppi * printable_width, INCH));
4780  printable_display_height =
4781    MAX(3, ROUNDUP(preview_ppi * printable_height, INCH));
4782
4783  printable_display_left = paper_display_left + preview_ppi * left / INCH;
4784  printable_display_top  = paper_display_top + preview_ppi * top / INCH ;
4785
4786  preview_x =
4787    1 + paper_display_left + preview_ppi * stp_get_left (pv->v) / INCH;
4788  preview_y =
4789    1 + paper_display_top + preview_ppi * stp_get_top (pv->v) / INCH;
4790
4791  if (!preview_valid)
4792    {
4793      gint preview_r = 1 + paper_display_left + preview_ppi * l_right / INCH;
4794      gint preview_b = 1 + paper_display_top + preview_ppi * l_bottom / INCH;
4795      preview_w = preview_r - preview_x;
4796      preview_h = preview_b - preview_y;
4797      if (preview_w >= printable_display_width)
4798	preview_w = printable_display_width - 1;
4799      if (preview_h >= printable_display_height)
4800	preview_h = printable_display_height - 1;
4801    }
4802
4803  if (preview_w + preview_x > printable_display_left + printable_display_width)
4804    preview_x--;
4805  if (preview_h + preview_y > printable_display_top + printable_display_height)
4806    preview_y--;
4807
4808  if (gc == NULL)
4809    {
4810      gc = gdk_gc_new (preview->widget.window);
4811      gcinv = gdk_gc_new (preview->widget.window);
4812      gdk_gc_set_function (gcinv, GDK_INVERT);
4813      gcset = gdk_gc_new (preview->widget.window);
4814      gdk_gc_set_function (gcset, GDK_SET);
4815    }
4816
4817  if (!preview_valid)
4818    create_valid_preview(&preview_data);
4819
4820  if (printable_display_left < paper_display_left)
4821    printable_display_left = paper_display_left;
4822  if (printable_display_top < paper_display_top)
4823    printable_display_top = paper_display_top;
4824  if (printable_display_left + printable_display_width >
4825      paper_display_left + paper_display_width)
4826    printable_display_width =
4827      paper_display_width - (paper_display_left - printable_display_left);
4828  if (printable_display_top + printable_display_height >
4829      paper_display_top + paper_display_height)
4830    printable_display_height =
4831      paper_display_height - (paper_display_top - printable_display_top);
4832  if (need_exposure)
4833    {
4834      if (!frame_valid)
4835	{
4836	  gdk_window_clear (preview->widget.window);
4837	  frame_valid = TRUE;
4838	}
4839      /* draw paper frame */
4840      gdk_draw_rectangle (preview->widget.window, gc, 0,
4841			  paper_display_left, paper_display_top,
4842			  paper_display_width, paper_display_height);
4843
4844      /* draw printable frame */
4845      gdk_draw_rectangle (preview->widget.window, gc, 0,
4846			  printable_display_left, printable_display_top,
4847			  printable_display_width, printable_display_height);
4848      need_exposure = FALSE;
4849    }
4850  else if (!frame_valid)
4851    {
4852      gdk_window_clear (preview->widget.window);
4853      /* draw paper frame */
4854      gdk_draw_rectangle (preview->widget.window, gc, 0,
4855			  paper_display_left, paper_display_top,
4856			  paper_display_width, paper_display_height);
4857
4858      /* draw printable frame */
4859      gdk_draw_rectangle (preview->widget.window, gc, 0,
4860			  printable_display_left, printable_display_top,
4861			  printable_display_width, printable_display_height);
4862      frame_valid = TRUE;
4863    }
4864  else
4865    {
4866      if (opx + opw <= preview_x || opy + oph <= preview_y ||
4867	  preview_x + preview_w <= opx || preview_y + preview_h <= opy)
4868        {
4869          gdk_window_clear_area (preview->widget.window, opx, opy, opw, oph);
4870        }
4871      else
4872	{
4873	  if (opx < preview_x)
4874	    gdk_window_clear_area (preview->widget.window,
4875                                   opx, opy, preview_x - opx, oph);
4876	  if (opy < preview_y)
4877	    gdk_window_clear_area (preview->widget.window,
4878                                   opx, opy, opw, preview_y - opy);
4879	  if (opx + opw > preview_x + preview_w)
4880	    gdk_window_clear_area (preview->widget.window,
4881                                   preview_x + preview_w, opy,
4882                                   (opx + opw) - (preview_x + preview_w), oph);
4883	  if (opy + oph > preview_y + preview_h)
4884	    gdk_window_clear_area (preview->widget.window,
4885                                   opx, preview_y + preview_h,
4886                                   opw, (opy + oph) - (preview_y + preview_h));
4887	}
4888    }
4889
4890  draw_arrow (preview->widget.window, gcset, paper_display_left,
4891	      paper_display_top);
4892
4893  if (!preview_valid)
4894    gdk_draw_rectangle (preview->widget.window, gc, 1,
4895			preview_x, preview_y, preview_w, preview_h);
4896  else if (!print_mode_is_color(pv->v))
4897    gdk_draw_gray_image (preview->widget.window, gc,
4898			 preview_x, preview_y, preview_w, preview_h,
4899			 GDK_RGB_DITHER_NORMAL, preview_data, preview_w);
4900  else
4901    gdk_draw_rgb_image (preview->widget.window, gc,
4902			preview_x, preview_y, preview_w, preview_h,
4903			GDK_RGB_DITHER_NORMAL, preview_data, 3 * preview_w);
4904
4905  /* If we're printing full bleed, redisplay the paper frame */
4906  if (preview_x <= paper_display_left || opx <= paper_display_left ||
4907      preview_y <= paper_display_top || opy <= paper_display_top ||
4908      preview_x + preview_w >= paper_display_left + paper_display_width ||
4909      opx + opw >= paper_display_left + paper_display_width ||
4910      preview_y + preview_h >= paper_display_top + paper_display_height ||
4911      opy + oph >= paper_display_top + paper_display_height)
4912    gdk_draw_rectangle (preview->widget.window, gc, 0,
4913			paper_display_left, paper_display_top,
4914			paper_display_width, paper_display_height);
4915
4916
4917  /* draw orientation arrow pointing to top-of-paper */
4918  draw_arrow (preview->widget.window, gcinv, paper_display_left,
4919	      paper_display_top);
4920  gdk_flush();
4921}
4922
4923static gboolean
4924idle_preview_thumbnail(gpointer data)
4925{
4926  if (thumbnail_data && adjusted_thumbnail_data && do_update_thumbnail)
4927    {
4928      thumbnail_update_pending = TRUE;
4929      set_orientation(pv->orientation);
4930      if (thumbnail_needs_rebuild && compute_thumbnail(pv->v))
4931	{
4932	  set_thumbnail_orientation();
4933	  redraw_color_swatch ();
4934	}
4935      do_preview_thumbnail();
4936    }
4937  thumbnail_update_pending = FALSE;
4938  return FALSE;
4939}
4940
4941static void
4942update_adjusted_thumbnail (gboolean regenerate_image)
4943{
4944  if (regenerate_image)
4945    thumbnail_needs_rebuild = TRUE;
4946  preview_update ();
4947}
4948
4949static void
4950preview_expose (void)
4951{
4952  need_exposure = TRUE;
4953  preview_update ();
4954}
4955
4956static void
4957preview_update (void)
4958{
4959  gdouble max_ppi_scaling;   /* Maximum PPI for current page size */
4960  gdouble min_ppi_scaling;   /* Minimum PPI for current page size */
4961
4962  suppress_preview_update++;
4963  compute_printable_region();
4964
4965  if (pv->scaling < 0)
4966    {
4967      gdouble twidth;
4968
4969      compute_scaling_limits(&min_ppi_scaling, &max_ppi_scaling);
4970
4971      if (pv->scaling < 0 && pv->scaling > -min_ppi_scaling)
4972	pv->scaling = -min_ppi_scaling;
4973
4974      twidth = (FINCH * (gdouble) image_width / -pv->scaling);
4975      print_width = twidth + .5;
4976      print_height = (twidth * (gdouble) image_height / image_width) + .5;
4977      GTK_ADJUSTMENT (scaling_adjustment)->lower = min_ppi_scaling;
4978      GTK_ADJUSTMENT (scaling_adjustment)->upper = max_ppi_scaling;
4979      GTK_ADJUSTMENT (scaling_adjustment)->value = -pv->scaling;
4980
4981      if (!suppress_scaling_adjustment)
4982	{
4983	  suppress_preview_reset++;
4984	  gtk_adjustment_changed (GTK_ADJUSTMENT (scaling_adjustment));
4985	  suppress_scaling_callback = TRUE;
4986	  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scaling_ppi), TRUE);
4987	  suppress_scaling_callback = FALSE;
4988	  gtk_adjustment_value_changed (GTK_ADJUSTMENT (scaling_adjustment));
4989	  suppress_preview_reset--;
4990	}
4991    }
4992  else if (auto_paper_size)
4993    {
4994      gdouble twidth = printable_width * pv->scaling / 100;
4995
4996      print_width = twidth + .5;
4997      print_height =
4998	(twidth * (gdouble) image_height / (gdouble) image_width) + .5;
4999    }
5000  else
5001    {
5002      /* we do pv->scaling % of height or width, whatever is less */
5003      /* this is relative to printable size */
5004      if (image_width * printable_height > printable_width * image_height)
5005	/* if image_width/image_height > printable_width/printable_height */
5006	/* i.e. if image is wider relative to its height than the width
5007	   of the printable area relative to its height */
5008	{
5009	  gdouble twidth = printable_width * pv->scaling / 100;
5010
5011	  print_width = twidth + .5;
5012	  print_height =
5013	    (twidth * (gdouble) image_height / (gdouble) image_width) + .5;
5014	}
5015      else
5016	{
5017	  gdouble theight = printable_height * pv->scaling /100;
5018
5019	  print_height = theight + .5;
5020	  print_width =
5021	    (theight * (gdouble) image_width / (gdouble) image_height) + .5;
5022	}
5023    }
5024
5025  if (auto_paper_size)
5026    set_media_size(stp_get_string_parameter(pv->v, "PageSize"));
5027
5028  stp_set_width(pv->v, print_width);
5029  stp_set_height(pv->v, print_height);
5030
5031  if (pv->invalid_mask & INVALID_LEFT)
5032    stp_set_left (pv->v, (paper_width - print_width) / 2);
5033
5034  if (stp_get_left(pv->v) < left)
5035    stp_set_left(pv->v, left);
5036
5037  if (stp_get_left (pv->v) > right - print_width)
5038    stp_set_left (pv->v, right - print_width);
5039
5040  if (pv->invalid_mask & INVALID_TOP)
5041    stp_set_top (pv->v, ((paper_height - print_height) / 2));
5042  if (stp_get_top(pv->v) < top)
5043    stp_set_top(pv->v, top);
5044
5045  if (stp_get_top (pv->v) > bottom - print_height)
5046    stp_set_top (pv->v, bottom - print_height);
5047
5048  pv->invalid_mask = 0;
5049
5050  set_all_entry_values();
5051  suppress_preview_update--;
5052
5053  /* draw image */
5054  if (! suppress_preview_update && !thumbnail_update_pending)
5055    {
5056      thumbnail_update_pending = TRUE;
5057      g_idle_add(idle_preview_thumbnail, NULL);
5058    }
5059}
5060
5061/*
5062 *  preview_button_callback() -
5063 */
5064static void
5065preview_button_callback (GtkWidget      *widget,
5066			 GdkEventButton *event,
5067			 gpointer        data)
5068{
5069  if (event->type == GDK_BUTTON_PRESS)
5070    {
5071      if (preview_active == 0)
5072	{
5073	  mouse_x = event->x;
5074	  mouse_y = event->y;
5075	  orig_left = stp_get_left (pv->v);
5076	  orig_top = stp_get_top (pv->v);
5077	  mouse_button = event->button;
5078	  buttons_mask = 1 << event->button;
5079	  buttons_pressed++;
5080	  preview_active = 1;
5081	  stpui_disable_help();
5082	  move_constraint =
5083	    (event->state & GDK_SHIFT_MASK) ? MOVE_CONSTRAIN : MOVE_ANY;
5084	  if (event->state & GDK_CONTROL_MASK)
5085	    move_constraint |= MOVE_GRID;
5086	}
5087      else if ((buttons_mask & (1 << event->button)) == 0)
5088	{
5089	  if (preview_active == 1)
5090	    {
5091	      stpui_enable_help();
5092	      preview_active = -1;
5093	      stp_set_left (pv->v, orig_left);
5094	      stp_set_top (pv->v, orig_top);
5095	      preview_update ();
5096	    }
5097	  buttons_mask |= 1 << event->button;
5098	  buttons_pressed++;
5099	}
5100    }
5101  else if (event->type == GDK_BUTTON_RELEASE)
5102    {
5103      buttons_pressed--;
5104      buttons_mask &= ~(1 << event->button);
5105      if (buttons_pressed == 0)
5106	{
5107	  stpui_enable_help ();
5108	  preview_active = 0;
5109	}
5110    }
5111}
5112
5113/*
5114 *  preview_motion_callback() -
5115 */
5116static void
5117preview_motion_callback (GtkWidget      *widget,
5118			 GdkEventMotion *event,
5119			 gpointer        data)
5120{
5121
5122  gint old_top  = stp_get_top (pv->v);
5123  gint old_left = stp_get_left (pv->v);
5124  gint new_top  = old_top;
5125  gint new_left = old_left;
5126  gint steps;
5127  if (preview_active != 1 || event->type != GDK_MOTION_NOTIFY)
5128    return;
5129  if (move_constraint == MOVE_CONSTRAIN)
5130    {
5131      int dx = abs(event->x - mouse_x);
5132      int dy = abs(event->y - mouse_y);
5133      if (dx > dy && dx > 3)
5134	move_constraint = MOVE_HORIZONTAL;
5135      else if (dy > dx && dy > 3)
5136	move_constraint = MOVE_VERTICAL;
5137      else
5138	return;
5139    }
5140
5141  switch (mouse_button)
5142    {
5143    case 1:
5144      if (move_constraint & MOVE_VERTICAL)
5145	new_top = orig_top + INCH * (event->y - mouse_y) / preview_ppi;
5146      if (move_constraint & MOVE_HORIZONTAL)
5147	new_left = orig_left + INCH * (event->x - mouse_x) / preview_ppi;
5148      break;
5149    case 3:
5150      if (move_constraint & MOVE_VERTICAL)
5151	new_top = orig_top + event->y - mouse_y;
5152      if (move_constraint & MOVE_HORIZONTAL)
5153	new_left = orig_left + event->x - mouse_x;
5154      break;
5155    case 2:
5156      if (move_constraint & MOVE_HORIZONTAL)
5157	{
5158	  gint increment_width =
5159	    ((move_constraint & MOVE_GRID) && pv->scaling > 0) ?
5160	    printable_width * pv->scaling / 100 : print_width;
5161	  gint x_threshold = MAX (1, (preview_ppi * increment_width) / INCH);
5162	  if (event->x > mouse_x)
5163	    steps = MIN((event->x - mouse_x) / x_threshold,
5164			((right - orig_left) / increment_width) - 1);
5165	  else
5166	    steps = -(MIN((mouse_x - event->x) / x_threshold,
5167			  (orig_left - left) / increment_width));
5168	  new_left = orig_left + steps * increment_width;
5169	}
5170      if (move_constraint & MOVE_VERTICAL)
5171	{
5172	  gint increment_height =
5173	    ((move_constraint & MOVE_GRID) && pv->scaling > 0) ?
5174	    printable_height * pv->scaling / 100 : print_height;
5175	  gint y_threshold = MAX (1, (preview_ppi * increment_height) / INCH);
5176	  if (event->y > mouse_y)
5177	    steps = MIN((event->y - mouse_y) / y_threshold,
5178			((bottom - orig_top) / increment_height) - 1);
5179	  else
5180	    steps = -(MIN((mouse_y - event->y) / y_threshold,
5181			  (orig_top - top) / increment_height));
5182	  new_top = orig_top + steps * increment_height;
5183	}
5184      break;
5185    }
5186
5187  if (new_top < top)
5188    new_top = top;
5189  if (new_top > bottom - print_height)
5190    new_top = bottom - print_height;
5191  if (new_left < left)
5192    new_left = left;
5193  if (new_left > right - print_width)
5194    new_left = right - print_width;
5195
5196  if (new_top != old_top || new_left != old_left)
5197    {
5198      stp_set_top (pv->v, new_top);
5199      stp_set_left (pv->v, new_left);
5200      preview_update ();
5201    }
5202}
5203
5204static void
5205color_update (GtkAdjustment *adjustment)
5206{
5207  int i;
5208  for (i = 0; i < current_option_count; i++)
5209    {
5210      option_t *opt = &(current_options[i]);
5211      if (opt->fast_desc->p_type == STP_PARAMETER_TYPE_DOUBLE &&
5212	  opt->fast_desc->p_level <= MAXIMUM_PARAMETER_LEVEL &&
5213	  opt->info.flt.adjustment &&
5214	  adjustment == GTK_ADJUSTMENT(opt->info.flt.adjustment))
5215	{
5216	  invalidate_preview_thumbnail ();
5217	  if (stp_get_float_parameter(pv->v, opt->fast_desc->name) !=
5218	      adjustment->value)
5219	    {
5220	      stp_set_float_parameter(pv->v, opt->fast_desc->name,
5221				      adjustment->value);
5222	      update_adjusted_thumbnail(TRUE);
5223	    }
5224	}
5225    }
5226}
5227
5228static void
5229dimension_update (GtkAdjustment *adjustment)
5230{
5231  int i;
5232  gdouble unit_scaler = units[pv->unit].scale;
5233  for (i = 0; i < current_option_count; i++)
5234    {
5235      option_t *opt = &(current_options[i]);
5236      if (opt->fast_desc->p_type == STP_PARAMETER_TYPE_DIMENSION &&
5237	  opt->fast_desc->p_level <= MAXIMUM_PARAMETER_LEVEL &&
5238	  opt->info.flt.adjustment &&
5239	  adjustment == GTK_ADJUSTMENT(opt->info.flt.adjustment))
5240	{
5241	  int new_value = (adjustment->value + (.5 / unit_scaler)) * unit_scaler;
5242	  invalidate_preview_thumbnail ();
5243	  if (stp_get_dimension_parameter(pv->v, opt->fast_desc->name) !=
5244	      new_value)
5245	    {
5246	      stp_set_dimension_parameter(pv->v, opt->fast_desc->name,
5247					  new_value);
5248	      update_adjusted_thumbnail(FALSE);
5249	    }
5250	}
5251    }
5252}
5253
5254static void
5255integer_update (GtkAdjustment *adjustment)
5256{
5257  int i;
5258  for (i = 0; i < current_option_count; i++)
5259    {
5260      option_t *opt = &(current_options[i]);
5261      if (opt->fast_desc->p_type == STP_PARAMETER_TYPE_INT &&
5262	  opt->fast_desc->p_level <= MAXIMUM_PARAMETER_LEVEL &&
5263	  opt->info.flt.adjustment &&
5264	  adjustment == GTK_ADJUSTMENT(opt->info.flt.adjustment))
5265	{
5266	  invalidate_preview_thumbnail ();
5267	  if (stp_get_int_parameter(pv->v, opt->fast_desc->name) !=
5268	      (int) adjustment->value)
5269	    {
5270	      stp_set_int_parameter(pv->v, opt->fast_desc->name,
5271				    (int) adjustment->value);
5272	      update_adjusted_thumbnail(FALSE);
5273	    }
5274	}
5275    }
5276}
5277
5278static void
5279set_controls_active (GtkObject *checkbutton, gpointer xopt)
5280{
5281  option_t *opt = (option_t *) xopt;
5282  stp_parameter_t desc;
5283  gboolean setting =
5284    gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton));
5285  if (setting && opt->fast_desc->p_level <= MAXIMUM_PARAMETER_LEVEL)
5286    {
5287      switch (opt->fast_desc->p_type)
5288	{
5289	case STP_PARAMETER_TYPE_DOUBLE:
5290	  set_adjustment_active(opt, TRUE, FALSE);
5291	  if (! stp_check_float_parameter(pv->v, opt->fast_desc->name,
5292					  STP_PARAMETER_INACTIVE))
5293	    {
5294	      stp_describe_parameter(pv->v, opt->fast_desc->name, &desc);
5295	      stp_set_float_parameter(pv->v, opt->fast_desc->name,
5296				      desc.deflt.dbl);
5297	      stp_parameter_description_destroy(&desc);
5298	    }
5299	  stp_set_float_parameter_active(pv->v, opt->fast_desc->name,
5300					 STP_PARAMETER_ACTIVE);
5301	  break;
5302	case STP_PARAMETER_TYPE_DIMENSION:
5303	  set_adjustment_active(opt, TRUE, FALSE);
5304	  if (! stp_check_dimension_parameter(pv->v, opt->fast_desc->name,
5305					      STP_PARAMETER_INACTIVE))
5306	    {
5307	      stp_describe_parameter(pv->v, opt->fast_desc->name, &desc);
5308	      stp_set_dimension_parameter(pv->v, opt->fast_desc->name,
5309					  desc.deflt.dimension);
5310	      stp_parameter_description_destroy(&desc);
5311	    }
5312	  stp_set_dimension_parameter_active(pv->v, opt->fast_desc->name,
5313					     STP_PARAMETER_ACTIVE);
5314	  break;
5315	case STP_PARAMETER_TYPE_INT:
5316	  set_adjustment_active(opt, TRUE, FALSE);
5317	  if (! stp_check_int_parameter(pv->v, opt->fast_desc->name,
5318					    STP_PARAMETER_INACTIVE))
5319	    {
5320	      stp_describe_parameter(pv->v, opt->fast_desc->name, &desc);
5321	      stp_set_int_parameter(pv->v, opt->fast_desc->name,
5322				    desc.deflt.integer);
5323	      stp_parameter_description_destroy(&desc);
5324	    }
5325	  stp_set_int_parameter_active(pv->v, opt->fast_desc->name,
5326				       STP_PARAMETER_ACTIVE);
5327	  break;
5328	case STP_PARAMETER_TYPE_CURVE:
5329	  set_curve_active(opt, TRUE, FALSE);
5330	  if (! stp_check_curve_parameter(pv->v, opt->fast_desc->name,
5331					  STP_PARAMETER_INACTIVE))
5332	    {
5333	      stp_describe_parameter(pv->v, opt->fast_desc->name, &desc);
5334	      stp_set_curve_parameter(pv->v, opt->fast_desc->name,
5335				      desc.deflt.curve);
5336	      stp_parameter_description_destroy(&desc);
5337	    }
5338	  stp_set_curve_parameter_active(pv->v, opt->fast_desc->name,
5339					 STP_PARAMETER_ACTIVE);
5340	  break;
5341	case STP_PARAMETER_TYPE_STRING_LIST:
5342	  set_combo_active(opt, TRUE, FALSE);
5343	  if (! stp_check_string_parameter(pv->v, opt->fast_desc->name,
5344					   STP_PARAMETER_INACTIVE))
5345	    {
5346	      stp_describe_parameter(pv->v, opt->fast_desc->name, &desc);
5347	      stp_set_string_parameter(pv->v, opt->fast_desc->name,
5348				       desc.deflt.str);
5349	      stp_parameter_description_destroy(&desc);
5350	    }
5351	  stp_set_string_parameter_active(pv->v, opt->fast_desc->name,
5352					  STP_PARAMETER_ACTIVE);
5353	  break;
5354	case STP_PARAMETER_TYPE_BOOLEAN:
5355	  set_bool_active(opt, TRUE, FALSE);
5356	  if (! stp_check_boolean_parameter(pv->v, opt->fast_desc->name,
5357					    STP_PARAMETER_INACTIVE))
5358	    {
5359	      stp_describe_parameter(pv->v, opt->fast_desc->name, &desc);
5360	      stp_set_boolean_parameter(pv->v, opt->fast_desc->name,
5361					desc.deflt.boolean);
5362	      stp_parameter_description_destroy(&desc);
5363	    }
5364	  stp_set_boolean_parameter_active(pv->v, opt->fast_desc->name,
5365					   STP_PARAMETER_ACTIVE);
5366	  break;
5367	case STP_PARAMETER_TYPE_FILE:
5368	  set_file_active(opt, TRUE, FALSE);
5369	  stp_set_file_parameter_active(pv->v, opt->fast_desc->name,
5370					STP_PARAMETER_ACTIVE);
5371	  break;
5372	default:
5373	  break;
5374	}
5375    }
5376  else
5377    {
5378      switch (opt->fast_desc->p_type)
5379	{
5380	case STP_PARAMETER_TYPE_DOUBLE:
5381	  set_adjustment_active(opt, FALSE, FALSE);
5382	  stp_set_float_parameter_active(pv->v, opt->fast_desc->name,
5383					 STP_PARAMETER_INACTIVE);
5384	  break;
5385	case STP_PARAMETER_TYPE_DIMENSION:
5386	  set_adjustment_active(opt, FALSE, FALSE);
5387	  stp_set_dimension_parameter_active(pv->v, opt->fast_desc->name,
5388					     STP_PARAMETER_INACTIVE);
5389	  break;
5390	case STP_PARAMETER_TYPE_INT:
5391	  set_adjustment_active(opt, FALSE, FALSE);
5392	  stp_set_int_parameter_active(pv->v, opt->fast_desc->name,
5393				       STP_PARAMETER_INACTIVE);
5394	  break;
5395	case STP_PARAMETER_TYPE_CURVE:
5396	  set_curve_active(opt, FALSE, FALSE);
5397	  stp_set_curve_parameter_active(pv->v, opt->fast_desc->name,
5398					 STP_PARAMETER_INACTIVE);
5399	  break;
5400	case STP_PARAMETER_TYPE_STRING_LIST:
5401	  set_combo_active(opt, FALSE, FALSE);
5402	  stp_set_string_parameter_active(pv->v, opt->fast_desc->name,
5403					  STP_PARAMETER_INACTIVE);
5404	  break;
5405	case STP_PARAMETER_TYPE_BOOLEAN: /* ??? */
5406	  set_bool_active(opt, FALSE, FALSE);
5407	  stp_set_boolean_parameter_active(pv->v, opt->fast_desc->name,
5408					   STP_PARAMETER_INACTIVE);
5409	  break;
5410	case STP_PARAMETER_TYPE_FILE: /* ??? */
5411	  set_file_active(opt, FALSE, FALSE);
5412	  stp_set_file_parameter_active(pv->v, opt->fast_desc->name,
5413					STP_PARAMETER_INACTIVE);
5414	  break;
5415	default:
5416	  break;
5417	}
5418    }
5419  invalidate_preview_thumbnail();
5420  update_adjusted_thumbnail(TRUE);
5421}
5422
5423static void
5424set_one_default(option_t *opt)
5425{
5426  stp_parameter_activity_t active;
5427  gdouble unit_scaler;
5428  switch (opt->fast_desc->p_type)
5429    {
5430    case STP_PARAMETER_TYPE_DOUBLE:
5431      active = stp_get_float_parameter_active(pv->v, opt->fast_desc->name);
5432      stp_set_float_parameter(pv->v, opt->fast_desc->name, opt->info.flt.deflt);
5433      stp_set_float_parameter_active(pv->v, opt->fast_desc->name, active);
5434      break;
5435    case STP_PARAMETER_TYPE_DIMENSION:
5436      unit_scaler = units[pv->unit].scale;
5437      active = stp_get_dimension_parameter_active(pv->v, opt->fast_desc->name);
5438      stp_set_dimension_parameter(pv->v, opt->fast_desc->name,
5439				  opt->info.flt.deflt * unit_scaler);
5440      stp_set_dimension_parameter_active(pv->v, opt->fast_desc->name, active);
5441      break;
5442    case STP_PARAMETER_TYPE_INT:
5443      unit_scaler = units[pv->unit].scale;
5444      active = stp_get_int_parameter_active(pv->v, opt->fast_desc->name);
5445      stp_set_int_parameter(pv->v, opt->fast_desc->name,
5446			    (int) opt->info.flt.deflt);
5447      stp_set_int_parameter_active(pv->v, opt->fast_desc->name, active);
5448      break;
5449    case STP_PARAMETER_TYPE_BOOLEAN:
5450      active = stp_get_boolean_parameter_active(pv->v, opt->fast_desc->name);
5451      stp_set_boolean_parameter(pv->v, opt->fast_desc->name,
5452				opt->info.bool.deflt);
5453      stp_set_boolean_parameter_active(pv->v, opt->fast_desc->name, active);
5454      break;
5455    case STP_PARAMETER_TYPE_STRING_LIST:
5456      active = stp_get_string_parameter_active(pv->v, opt->fast_desc->name);
5457      stp_set_string_parameter(pv->v, opt->fast_desc->name,
5458			       opt->info.list.default_val);
5459      stp_set_string_parameter_active(pv->v, opt->fast_desc->name, active);
5460      break;
5461    case STP_PARAMETER_TYPE_FILE:
5462      active = stp_get_file_parameter_active(pv->v, opt->fast_desc->name);
5463      stp_set_file_parameter(pv->v, opt->fast_desc->name, "");
5464      stp_set_file_parameter_active(pv->v, opt->fast_desc->name, active);
5465      break;
5466    default:
5467      break;
5468    }
5469}
5470
5471static void
5472reset_callback(GtkObject *button, gpointer xopt)
5473{
5474  option_t *opt = (option_t *)xopt;
5475  if (opt)
5476    {
5477      set_one_default(opt);
5478      if (opt->reset_all)
5479	do_all_updates ();
5480      else
5481	do_color_updates ();
5482    }
5483}
5484
5485static void
5486set_printer_defaults (void)
5487{
5488  int i;
5489  for (i = 0; i < current_option_count; i++)
5490    {
5491      option_t *opt = &(current_options[i]);
5492      if (opt->fast_desc->p_level <= MAXIMUM_PARAMETER_LEVEL &&
5493	  opt->fast_desc->p_class == STP_PARAMETER_CLASS_FEATURE &&
5494	  opt->is_active && !opt->fast_desc->read_only)
5495	set_one_default(opt);
5496    }
5497
5498  do_all_updates ();
5499}
5500
5501static void
5502set_color_defaults (void)
5503{
5504  int i;
5505  for (i = 0; i < current_option_count; i++)
5506    {
5507      option_t *opt = &(current_options[i]);
5508      if (opt->fast_desc->p_level <= MAXIMUM_PARAMETER_LEVEL &&
5509	  opt->fast_desc->p_class == STP_PARAMETER_CLASS_OUTPUT &&
5510	  opt->is_active && !opt->fast_desc->read_only)
5511	set_one_default(opt);
5512    }
5513
5514  do_color_updates ();
5515}
5516
5517gint
5518stpui_do_print_dialog(void)
5519{
5520  /*
5521   * Get printrc options...
5522   */
5523  stpui_printrc_load ();
5524
5525  /*
5526   * Print dialog window...
5527   */
5528  create_main_window();
5529
5530  gtk_main ();
5531  gdk_flush ();
5532
5533  /*
5534   * Set printrc options...
5535   */
5536  if (saveme)
5537    stpui_printrc_save ();
5538
5539  /*
5540   * Return ok/cancel...
5541   */
5542  return (runme);
5543}
5544