home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / resize.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  46.1 KB  |  1,408 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <gtk/gtk.h>
  22.  
  23. #include "apptypes.h"
  24.  
  25. #include "appenv.h"
  26. #include "gdisplay.h"
  27. #include "resize.h"
  28. #include "undo.h"
  29. #include "gimprc.h"
  30. #include "gimpui.h"
  31.  
  32. #include "libgimp/gimpchainbutton.h"
  33. #include "libgimp/gimplimits.h"
  34. #include "libgimp/gimpmath.h"
  35. #include "libgimp/gimpsizeentry.h"
  36.  
  37. #include "libgimp/gimpintl.h"
  38.  
  39. #define EVENT_MASK        GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK
  40. #define DRAWING_AREA_SIZE 200
  41. #define TEXT_WIDTH        35
  42.  
  43. typedef struct _ResizePrivate ResizePrivate;
  44.  
  45. struct _ResizePrivate
  46. {
  47.   /*  size frame  */
  48.   GtkWidget *orig_width_label;
  49.   GtkWidget *orig_height_label;
  50.  
  51.   GtkWidget *size_se;
  52.  
  53.   GtkObject *ratio_x_adj;
  54.   GtkObject *ratio_y_adj;
  55.   GtkWidget *constrain;
  56.  
  57.   /*  offset frame  */
  58.   GtkWidget *offset_se;
  59.   GtkWidget *drawing_area;
  60.  
  61.   /*  resolution frame  */
  62.   GtkWidget *printsize_se;
  63.   GtkWidget *resolution_se;
  64.   GtkWidget *equal_res;
  65.  
  66.   gdouble ratio;
  67.   gint    old_width, old_height;
  68.   gdouble old_res_x, old_res_y;
  69.   gint    area_width, area_height;
  70.   gint    start_x, start_y;
  71.   gint    orig_x, orig_y;
  72. };
  73.  
  74. static void  resize_draw                 (Resize    *resize);
  75. static void  unit_update                 (GtkWidget *widget,
  76.                       gpointer   data);
  77. static gint  resize_bound_off_x          (Resize    *resize,
  78.                       gint       off_x);
  79. static gint  resize_bound_off_y          (Resize    *resize,
  80.                       gint       off_y);
  81. static void  orig_labels_update          (GtkWidget *widget,
  82.                       gpointer   data);
  83. static void  reset_callback              (GtkWidget *widget,
  84.                       gpointer   data);
  85. static void  size_callback               (GtkWidget *widget,
  86.                       gpointer   data);
  87. static void  ratio_callback              (GtkWidget *widget,
  88.                       gpointer   data);
  89. static void  size_update                 (Resize    *widget,
  90.                       gdouble    width,
  91.                       gdouble    height,
  92.                       gdouble    ratio_x,
  93.                       gdouble    ratio_y);
  94. static void  offset_update               (GtkWidget *widget,
  95.                       gpointer   data);
  96. static gint  resize_events               (GtkWidget *widget,
  97.                       GdkEvent  *event);
  98. static void  printsize_update            (GtkWidget *widget,
  99.                       gpointer   data);
  100. static void  resolution_callback         (GtkWidget *widget,
  101.                       gpointer   data);
  102. static void  resolution_update           (Resize    *resize,
  103.                       gdouble    res_x,
  104.                       gdouble    res_y);
  105. static void  resize_scale_warn_callback  (GtkWidget *widget,
  106.                       gboolean   do_scale,
  107.                       gpointer   data);
  108.  
  109.  
  110. Resize *
  111. resize_widget_new (ResizeType    type,
  112.            ResizeTarget  target,
  113.            GtkObject    *object,
  114.            gchar        *signal,
  115.            gint          width,
  116.            gint          height,
  117.            gdouble       resolution_x,
  118.            gdouble       resolution_y,
  119.            GimpUnit      unit,
  120.            gboolean      dot_for_dot,
  121.            GtkSignalFunc ok_cb,
  122.            GtkSignalFunc cancel_cb,
  123.            gpointer      user_data)
  124. {
  125.   Resize *resize;
  126.   ResizePrivate *private;
  127.   GtkWidget *main_vbox;
  128.   GtkWidget *vbox;
  129.   GtkWidget *table;
  130.   GtkWidget *table2;
  131.   GtkWidget *label;
  132.   GtkWidget *frame;
  133.   GtkWidget *spinbutton;
  134.   GtkWidget *abox;
  135.   GtkObject *adjustment;
  136.  
  137.   abox = NULL;
  138.   frame = NULL;
  139.  
  140.   private = g_new0 (ResizePrivate, 1);
  141.   private->old_width  = width;
  142.   private->old_height = height;
  143.   private->old_res_x  = resolution_x;
  144.   private->old_res_y  = resolution_y;
  145.  
  146.   resize = g_new (Resize, 1);
  147.   resize->type         = type;
  148.   resize->target       = target;
  149.   resize->private_part = private;
  150.   resize->width        = width;
  151.   resize->height       = height;
  152.   resize->resolution_x = resolution_x;
  153.   resize->resolution_y = resolution_y;
  154.   resize->unit         = unit;
  155.   resize->ratio_x      = 1.0;
  156.   resize->ratio_y      = 1.0;
  157.   resize->offset_x     = 0;
  158.   resize->offset_y     = 0;
  159.  
  160.   /*  Get the image width and height variables, based on the gimage  */
  161.   if (width > height)
  162.     private->ratio = (gdouble) DRAWING_AREA_SIZE / (gdouble) width;
  163.   else
  164.     private->ratio = (gdouble) DRAWING_AREA_SIZE / (gdouble) height;
  165.  
  166.   private->area_width  = (gint) (private->ratio * width);
  167.   private->area_height = (gint) (private->ratio * height);
  168.  
  169.   /*  dialog box  */
  170.   {
  171.     const gchar *wmclass = NULL;
  172.     const gchar *window_title = NULL;
  173.     gchar *help_page = NULL;
  174.  
  175.     switch (type)
  176.       {
  177.       case ScaleWidget:
  178.     switch (target)
  179.       {
  180.       case ResizeLayer:
  181.         wmclass = "scale_layer";
  182.         window_title = _("Scale Layer");
  183.         help_page = "layers/dialogs/scale_layer.html";
  184.         frame = gtk_frame_new (_("Size"));
  185.         break;
  186.       case ResizeImage:
  187.         wmclass = "scale_image";
  188.         window_title = _("Scale Image");
  189.         help_page = "dialogs/scale_image.html";
  190.         frame = gtk_frame_new (_("Pixel Dimensions"));
  191.         break;
  192.       }
  193.     break;
  194.  
  195.       case ResizeWidget:
  196.     switch (target)
  197.       {
  198.       case ResizeLayer:
  199.         wmclass = "resize_layer";
  200.         window_title = _("Set Layer Boundary Size");
  201.         help_page = "layers/dialogs/layer_boundary_size.html";
  202.         break;
  203.       case ResizeImage:
  204.         wmclass = "resize_image";
  205.         window_title = _("Set Canvas Size");
  206.         help_page = "dialogs/set_canvas_size.html";
  207.         break;
  208.       }
  209.     frame = gtk_frame_new (_("Size"));
  210.     break;
  211.       }    
  212.  
  213.     resize->resize_shell =
  214.       gimp_dialog_new (window_title, wmclass,
  215.                gimp_standard_help_func, help_page,
  216.                GTK_WIN_POS_MOUSE,
  217.                FALSE, FALSE, TRUE,
  218.  
  219.                _("OK"), ok_cb,
  220.                user_data, NULL, NULL, TRUE, FALSE,
  221.  
  222.                _("Reset"), reset_callback,
  223.                resize, NULL, NULL, FALSE, FALSE,
  224.  
  225.                _("Cancel"), cancel_cb ? cancel_cb : gtk_widget_destroy,
  226.                cancel_cb ? user_data : NULL,
  227.                cancel_cb ? NULL : (gpointer) 1,
  228.                NULL, FALSE, TRUE,
  229.  
  230.                NULL);
  231.  
  232.     gtk_signal_connect_object (GTK_OBJECT (resize->resize_shell), "destroy",
  233.                    GTK_SIGNAL_FUNC (g_free),
  234.                    (GtkObject *) private);
  235.     gtk_signal_connect_object (GTK_OBJECT (resize->resize_shell), "destroy",
  236.                    GTK_SIGNAL_FUNC (g_free),
  237.                    (GtkObject *) resize);
  238.   }
  239.  
  240.   /*  handle the image disappearing under our feet  */
  241.   if (object && signal)
  242.     {
  243.       if (cancel_cb)
  244.     gtk_signal_connect (GTK_OBJECT (object), signal,
  245.                 cancel_cb,
  246.                 user_data);
  247.       else
  248.     gtk_signal_connect_object_while_alive
  249.       (GTK_OBJECT (object), signal,
  250.        GTK_SIGNAL_FUNC (gtk_widget_destroy),
  251.        GTK_OBJECT (resize->resize_shell));
  252.     }
  253.  
  254.   /*  the main vbox  */
  255.   main_vbox = gtk_vbox_new (FALSE, 4);
  256.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 4);
  257.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (resize->resize_shell)->vbox),
  258.              main_vbox);
  259.  
  260.   /*  the pixel dimensions frame  */
  261.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  262.   gtk_widget_show (frame);
  263.  
  264.   vbox = gtk_vbox_new (FALSE, 2);
  265.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  266.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  267.  
  268.   table = gtk_table_new (6, 2, FALSE);
  269.   gtk_container_set_border_width (GTK_CONTAINER (table), 2);
  270.   gtk_table_set_col_spacing (GTK_TABLE (table), 0, 4);
  271.   gtk_table_set_row_spacing (GTK_TABLE (table), 0, 4);
  272.   gtk_table_set_row_spacing (GTK_TABLE (table), 1, 4);
  273.   gtk_table_set_row_spacing (GTK_TABLE (table), 3, 4);
  274.   gtk_table_set_row_spacing (GTK_TABLE (table), 4, 2);
  275.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  276.  
  277.   /*  the original width & height labels  */
  278.   label = gtk_label_new (_("Original Width:"));
  279.   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  280.   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
  281.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  282.   gtk_widget_show (label);
  283.  
  284.   label = gtk_label_new (_("Height:"));
  285.   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  286.   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
  287.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  288.   gtk_widget_show (label);
  289.  
  290.   private->orig_width_label = gtk_label_new ("");
  291.   gtk_misc_set_alignment (GTK_MISC ( private->orig_width_label), 0.0, 0.5);
  292.   gtk_table_attach (GTK_TABLE (table),  private->orig_width_label, 1, 2, 0, 1,
  293.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  294.   gtk_widget_show ( private->orig_width_label);
  295.  
  296.   private->orig_height_label = gtk_label_new ("");
  297.   gtk_misc_set_alignment (GTK_MISC (private->orig_height_label), 0.0, 0.5);
  298.   gtk_table_attach (GTK_TABLE (table), private->orig_height_label, 1, 2, 1, 2,
  299.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  300.   gtk_widget_show (private->orig_height_label);
  301.  
  302.   /*  the new size labels  */
  303.   label = gtk_label_new (_("New Width:"));
  304.   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  305.   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
  306.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  307.   gtk_widget_show (label);
  308.  
  309.   label = gtk_label_new (_("Height:"));
  310.   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  311.   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
  312.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  313.   gtk_widget_show (label);
  314.  
  315.   /*  the new size sizeentry  */
  316.   adjustment = gtk_adjustment_new (1, 1, 1, 1, 10, 1);
  317.   spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), 1, 2);
  318.   gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinbutton),
  319.                                    GTK_SHADOW_NONE);
  320.   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
  321.   gtk_widget_set_usize (spinbutton, 75, 0);
  322.  
  323.   private->size_se =
  324.     gimp_size_entry_new (1, unit, "%a", TRUE, TRUE, FALSE, 75,
  325.              GIMP_SIZE_ENTRY_UPDATE_SIZE);
  326.   gimp_size_entry_add_field (GIMP_SIZE_ENTRY (private->size_se),
  327.                  GTK_SPIN_BUTTON (spinbutton), NULL);
  328.   gtk_table_attach_defaults (GTK_TABLE (private->size_se), spinbutton,
  329.                  1, 2, 0, 1);
  330.   gtk_widget_show (spinbutton);
  331.   gtk_table_attach (GTK_TABLE (table), private->size_se, 1, 2, 2, 4,
  332.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  333.   gtk_widget_show (private->size_se);
  334.  
  335.   if (dot_for_dot)
  336.     gimp_size_entry_set_unit (GIMP_SIZE_ENTRY (private->size_se),
  337.                   GIMP_UNIT_PIXEL);
  338.  
  339.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (private->size_se), 0,
  340.                   resolution_x, FALSE);
  341.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (private->size_se), 1,
  342.                   resolution_y, FALSE);
  343.  
  344.   gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (private->size_se), 0,
  345.                      GIMP_MIN_IMAGE_SIZE,
  346.                      GIMP_MAX_IMAGE_SIZE);
  347.   gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (private->size_se), 1,
  348.                      GIMP_MIN_IMAGE_SIZE,
  349.                      GIMP_MAX_IMAGE_SIZE);
  350.  
  351.   gimp_size_entry_set_size (GIMP_SIZE_ENTRY (private->size_se), 0, 0, width);
  352.   gimp_size_entry_set_size (GIMP_SIZE_ENTRY (private->size_se), 1, 0, height);
  353.  
  354.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->size_se), 0, width);
  355.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->size_se), 1, height);
  356.  
  357.   gtk_signal_connect (GTK_OBJECT (private->size_se), "value_changed",
  358.               GTK_SIGNAL_FUNC (size_callback),
  359.               resize);
  360.   gtk_signal_connect (GTK_OBJECT (private->size_se), "unit_changed",
  361.               GTK_SIGNAL_FUNC (orig_labels_update),
  362.               resize);
  363.  
  364.   /*  initialize the original width & height labels  */
  365.   orig_labels_update (private->size_se, resize);
  366.  
  367.   /*  the scale ratio labels  */
  368.   label = gtk_label_new (_("Ratio X:"));
  369.   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  370.   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5,
  371.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  372.   gtk_widget_show (label);
  373.  
  374.   label = gtk_label_new (_("Y:"));
  375.   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  376.   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 5, 6,
  377.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  378.   gtk_widget_show (label);
  379.  
  380.   /*  a table for the spinbuttons and the chainbutton  */
  381.   abox = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
  382.   table2 = gtk_table_new (2, 2, FALSE);
  383.   gtk_table_set_col_spacing (GTK_TABLE (table2), 0, 2);
  384.   gtk_table_set_row_spacing (GTK_TABLE (table2), 0, 2);
  385.   gtk_container_add (GTK_CONTAINER (abox), table2);
  386.   gtk_table_attach (GTK_TABLE (table), abox, 1, 2, 4, 6,
  387.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  388.   gtk_widget_show (abox);
  389.   
  390.   /*  the scale ratio spinbuttons  */
  391.   private->ratio_x_adj =
  392.     gtk_adjustment_new (resize->ratio_x, 
  393.             (double) GIMP_MIN_IMAGE_SIZE / (double) resize->width,
  394.             (double) GIMP_MAX_IMAGE_SIZE / (double) resize->width,
  395.             0.01, 0.1, 1);
  396.   spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (private->ratio_x_adj), 1, 4);
  397.   gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinbutton),
  398.                                    GTK_SHADOW_NONE);
  399.   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
  400.   gtk_widget_set_usize (spinbutton, 75, 0);
  401.   gtk_table_attach_defaults (GTK_TABLE (table2), spinbutton, 0, 1, 0, 1);
  402.   gtk_signal_connect (GTK_OBJECT ( private->ratio_x_adj), "value_changed",
  403.               (GtkSignalFunc) ratio_callback,
  404.               resize);
  405.   gtk_widget_show (spinbutton);
  406.  
  407.   private->ratio_y_adj =
  408.     gtk_adjustment_new (resize->ratio_y,
  409.             (double) GIMP_MIN_IMAGE_SIZE / (double) resize->height,
  410.             (double) GIMP_MAX_IMAGE_SIZE / (double) resize->height,
  411.             0.01, 0.1, 1);
  412.   spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (private->ratio_y_adj), 1, 4);
  413.   gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinbutton),
  414.                                    GTK_SHADOW_NONE);
  415.   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
  416.   gtk_widget_set_usize (spinbutton, 75, 0);
  417.   gtk_table_attach_defaults (GTK_TABLE (table2), spinbutton, 0, 1, 1, 2);
  418.   gtk_signal_connect (GTK_OBJECT ( private->ratio_y_adj), "value_changed",
  419.               (GtkSignalFunc) ratio_callback,
  420.               resize);
  421.   gtk_widget_show (spinbutton);
  422.  
  423.   /*  the constrain ratio chainbutton  */
  424.   private->constrain = gimp_chain_button_new (GIMP_CHAIN_RIGHT);
  425.   gimp_chain_button_set_active (GIMP_CHAIN_BUTTON (private->constrain), TRUE);
  426.   gtk_table_attach_defaults (GTK_TABLE (table2), private->constrain, 1, 2, 0, 2);
  427.   gtk_widget_show (private->constrain);
  428.  
  429.   gtk_widget_show (table2);
  430.   gtk_widget_show (table);
  431.   gtk_widget_show (vbox);
  432.  
  433.   /*  the offset frame  */
  434.   if (type == ResizeWidget)
  435.     {
  436.       frame = gtk_frame_new (_("Offset"));
  437.       gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  438.       gtk_widget_show (frame);
  439.  
  440.       vbox = gtk_vbox_new (FALSE, 4);
  441.       gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  442.       gtk_container_add (GTK_CONTAINER (frame), vbox);
  443.  
  444.       abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  445.       gtk_box_pack_start (GTK_BOX (vbox), abox, FALSE, FALSE, 0);
  446.  
  447.       /*  the offset sizeentry  */
  448.       adjustment = gtk_adjustment_new (1, 1, 1, 1, 10, 1);
  449.       spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), 1, 2);
  450.       gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinbutton),
  451.                        GTK_SHADOW_NONE);
  452.       gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
  453.       gtk_widget_set_usize (spinbutton, 75, 0);
  454.  
  455.       private->offset_se =
  456.     gimp_size_entry_new (1, unit, "%a", TRUE, FALSE, FALSE, 75,
  457.                  GIMP_SIZE_ENTRY_UPDATE_SIZE);
  458.       gimp_size_entry_add_field (GIMP_SIZE_ENTRY (private->offset_se),
  459.                  GTK_SPIN_BUTTON (spinbutton), NULL);
  460.       gtk_table_attach_defaults (GTK_TABLE (private->offset_se), spinbutton,
  461.                  1, 2, 0, 1);
  462.       gtk_table_set_col_spacing (GTK_TABLE (private->offset_se), 0, 4);
  463.       gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (private->offset_se),
  464.                     _("X:"), 0, 0, 1.0);
  465.       gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (private->offset_se),
  466.                     _("Y:"), 1, 0, 1.0);
  467.       gtk_widget_show (spinbutton);
  468.       gtk_container_add (GTK_CONTAINER (abox), private->offset_se);
  469.       gtk_widget_show (private->offset_se);
  470.  
  471.       if (dot_for_dot)
  472.     gimp_size_entry_set_unit (GIMP_SIZE_ENTRY (private->offset_se),
  473.                   GIMP_UNIT_PIXEL);
  474.  
  475.       gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (private->offset_se), 0,
  476.                       resolution_x, FALSE);
  477.       gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (private->offset_se), 1,
  478.                       resolution_y, FALSE);
  479.  
  480.       gimp_size_entry_set_refval_boundaries
  481.     (GIMP_SIZE_ENTRY (private->offset_se), 0, 0, 0);
  482.       gimp_size_entry_set_refval_boundaries
  483.     (GIMP_SIZE_ENTRY (private->offset_se), 1, 0, 0);
  484.  
  485.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->offset_se), 0, 0);
  486.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->offset_se), 1, 0);
  487.  
  488.       gtk_signal_connect (GTK_OBJECT (private->offset_se), "value_changed",
  489.               GTK_SIGNAL_FUNC (offset_update),
  490.               resize);
  491.  
  492.       gtk_widget_show (abox);
  493.  
  494.       /*  frame to hold drawing area  */
  495.       abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  496.       gtk_box_pack_start (GTK_BOX (vbox), abox, FALSE, FALSE, 0);
  497.  
  498.       frame = gtk_frame_new (NULL);
  499.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  500.       gtk_container_add (GTK_CONTAINER (abox), frame);
  501.  
  502.       private->drawing_area = gtk_drawing_area_new ();
  503.       gtk_drawing_area_size (GTK_DRAWING_AREA (private->drawing_area),
  504.                  private->area_width, private->area_height);
  505.       gtk_widget_set_events (private->drawing_area, EVENT_MASK);
  506.       gtk_signal_connect (GTK_OBJECT (private->drawing_area), "event",
  507.               GTK_SIGNAL_FUNC (resize_events),
  508.               NULL);
  509.       gtk_object_set_user_data (GTK_OBJECT (private->drawing_area), resize);
  510.       gtk_container_add (GTK_CONTAINER (frame), private->drawing_area);
  511.       gtk_widget_show (private->drawing_area);
  512.       gtk_widget_show (frame);
  513.  
  514.       gtk_widget_show (abox);
  515.       gtk_widget_show (vbox);
  516.     }
  517.  
  518.   /*  the resolution stuff  */
  519.   if ((type == ScaleWidget) && (target == ResizeImage))
  520.     {
  521.       frame = gtk_frame_new (_("Print Size & Display Unit"));
  522.       gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  523.       gtk_widget_show (frame);
  524.  
  525.       vbox = gtk_vbox_new (FALSE, 2);
  526.       gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  527.       gtk_container_add (GTK_CONTAINER (frame), vbox);
  528.  
  529.       table = gtk_table_new (4, 2, FALSE);
  530.       gtk_table_set_col_spacing (GTK_TABLE (table), 0, 4);
  531.       gtk_table_set_row_spacing (GTK_TABLE (table), 1, 4);
  532.       gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  533.  
  534.       /*  the print size labels  */
  535.       label = gtk_label_new (_("New Width:"));
  536.       gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  537.       gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
  538.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  539.       gtk_widget_show (label);
  540.  
  541.       label = gtk_label_new (_("Height:"));
  542.       gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  543.       gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
  544.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  545.       gtk_widget_show (label);
  546.  
  547.       /*  the print size sizeentry  */
  548.       abox = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
  549.       adjustment = gtk_adjustment_new (1, 1, 1, 1, 10, 1);
  550.       spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), 1, 2);
  551.       gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinbutton),
  552.                        GTK_SHADOW_NONE);
  553.       gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
  554.       gtk_widget_set_usize (spinbutton, 75, 0);
  555.       gtk_container_add (GTK_CONTAINER (abox), spinbutton);
  556.       gtk_widget_show (spinbutton);
  557.       gtk_table_attach (GTK_TABLE (table), abox, 1, 2, 0, 1,
  558.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  559.       gtk_widget_show (abox);
  560.  
  561.       abox = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
  562.       private->printsize_se =
  563.     gimp_size_entry_new (1, unit, "%a", FALSE, FALSE, FALSE, 75,
  564.                  GIMP_SIZE_ENTRY_UPDATE_SIZE);
  565.       gimp_size_entry_add_field (GIMP_SIZE_ENTRY (private->printsize_se),
  566.                  GTK_SPIN_BUTTON (spinbutton), NULL);
  567.       gtk_container_add (GTK_CONTAINER (abox), private->printsize_se);
  568.       gtk_table_attach (GTK_TABLE (table), abox, 1, 2, 1, 2,
  569.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  570.       gtk_widget_show (private->printsize_se);
  571.       gtk_widget_show (abox);
  572.  
  573.       gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (private->printsize_se),
  574.                       0, resolution_x, FALSE);
  575.       gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (private->printsize_se),
  576.                       1, resolution_y, FALSE);
  577.  
  578.       gimp_size_entry_set_refval_boundaries
  579.     (GIMP_SIZE_ENTRY (private->printsize_se),
  580.      0, GIMP_MIN_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE);
  581.       gimp_size_entry_set_refval_boundaries
  582.     (GIMP_SIZE_ENTRY (private->printsize_se),
  583.      1, GIMP_MIN_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE);
  584.  
  585.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->printsize_se),
  586.                   0, resize->width);
  587.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->printsize_se),
  588.                   1, resize->height);
  589.  
  590.       gtk_signal_connect (GTK_OBJECT (private->printsize_se), "value_changed",
  591.               GTK_SIGNAL_FUNC (printsize_update),
  592.               resize);
  593.       gtk_signal_connect (GTK_OBJECT (private->printsize_se), "unit_changed",
  594.               GTK_SIGNAL_FUNC (unit_update),
  595.               resize);
  596.       
  597.       /*  the resolution labels  */
  598.       label = gtk_label_new (_("Resolution X:"));
  599.       gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  600.       gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
  601.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  602.       gtk_widget_show (label);
  603.  
  604.       label = gtk_label_new (_("Y:"));
  605.       gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  606.       gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
  607.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  608.       gtk_widget_show (label);
  609.  
  610.       /*  the resolution sizeentry  */
  611.       adjustment = gtk_adjustment_new (1, 1, 1, 1, 10, 1);
  612.       spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), 1, 2);
  613.       gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinbutton),
  614.                        GTK_SHADOW_NONE);
  615.       gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
  616.       gtk_widget_set_usize (spinbutton, 75, 0);
  617.  
  618.       private->resolution_se =
  619.     gimp_size_entry_new (1, default_resolution_units, _("pixels/%a"),
  620.                  FALSE, FALSE, FALSE, 75,
  621.                  GIMP_SIZE_ENTRY_UPDATE_RESOLUTION);
  622.       gtk_table_set_col_spacing (GTK_TABLE (private->resolution_se), 1, 2);
  623.       gtk_table_set_col_spacing (GTK_TABLE (private->resolution_se), 2, 2);
  624.       gimp_size_entry_add_field (GIMP_SIZE_ENTRY (private->resolution_se),
  625.                  GTK_SPIN_BUTTON (spinbutton), NULL);
  626.       gtk_table_attach_defaults (GTK_TABLE (private->resolution_se), spinbutton,
  627.                  1, 2, 0, 1);
  628.       gtk_widget_show (spinbutton);
  629.       gtk_table_attach (GTK_TABLE (table), private->resolution_se, 1, 2, 2, 4,
  630.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  631.       gtk_widget_show (private->resolution_se);
  632.  
  633.       gimp_size_entry_set_refval_boundaries
  634.     (GIMP_SIZE_ENTRY (private->resolution_se),
  635.      0, GIMP_MIN_RESOLUTION, GIMP_MAX_RESOLUTION);
  636.       gimp_size_entry_set_refval_boundaries
  637.     (GIMP_SIZE_ENTRY (private->resolution_se),
  638.      1, GIMP_MIN_RESOLUTION, GIMP_MAX_RESOLUTION);
  639.  
  640.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->resolution_se),
  641.                   0, resize->resolution_x);
  642.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->resolution_se),
  643.                   1, resize->resolution_y);
  644.  
  645.       gtk_signal_connect (GTK_OBJECT (private->resolution_se), "value_changed",
  646.               GTK_SIGNAL_FUNC (resolution_callback),
  647.               resize);
  648.  
  649.       /*  the resolution chainbutton  */
  650.       private->equal_res = gimp_chain_button_new (GIMP_CHAIN_RIGHT);
  651.       gimp_chain_button_set_active
  652.     (GIMP_CHAIN_BUTTON (private->equal_res),
  653.      ABS (resize->resolution_x - resize->resolution_y) < 1e-5);
  654.       gtk_table_attach_defaults (GTK_TABLE (private->resolution_se),
  655.                  private->equal_res, 2, 3, 0, 2);
  656.       gtk_widget_show (private->equal_res);
  657.  
  658.       gtk_widget_show (table);
  659.       gtk_widget_show (vbox);
  660.     }
  661.  
  662.   gtk_widget_show (main_vbox);
  663.  
  664.   /*  finally, activate the first entry  */
  665.   gimp_size_entry_grab_focus (GIMP_SIZE_ENTRY (private->size_se));
  666.  
  667.   return resize;
  668. }
  669.  
  670. static void
  671. resize_draw (Resize *resize)
  672. {
  673.   GtkWidget *widget;
  674.   ResizePrivate *private;
  675.   gint aw, ah;
  676.   gint x, y;
  677.   gint w, h;
  678.  
  679.   /*  Only need to draw if it's a resize widget  */
  680.   if (resize->type != ResizeWidget)
  681.     return;
  682.  
  683.   private = (ResizePrivate *) resize->private_part;
  684.   widget = private->drawing_area;
  685.  
  686.   /*  If we're making the size larger  */
  687.   if (private->old_width <= resize->width)
  688.     w = resize->width;
  689.   /*  otherwise, if we're making the size smaller  */
  690.   else
  691.     w = private->old_width * 2 - resize->width;
  692.   /*  If we're making the size larger  */
  693.   if (private->old_height <= resize->height)
  694.     h = resize->height;
  695.   /*  otherwise, if we're making the size smaller  */
  696.   else
  697.     h = private->old_height * 2 - resize->height;
  698.  
  699.   if (w > h)
  700.     private->ratio = (gdouble) DRAWING_AREA_SIZE / (gdouble) w;
  701.   else
  702.     private->ratio = (gdouble) DRAWING_AREA_SIZE / (gdouble) h;
  703.  
  704.   aw = (gint) (private->ratio * w);
  705.   ah = (gint) (private->ratio * h);
  706.  
  707.   if (aw != private->area_width || ah != private->area_height)
  708.     {
  709.       private->area_width  = aw;
  710.       private->area_height = ah;
  711.       gtk_drawing_area_size (GTK_DRAWING_AREA (private->drawing_area), aw, ah);
  712.     }
  713.  
  714.   if (private->old_width <= resize->width)
  715.     x = private->ratio * resize->offset_x;
  716.   else
  717.     x = private->ratio * (resize->offset_x + private->old_width - resize->width);
  718.   if (private->old_height <= resize->height)
  719.     y = private->ratio * resize->offset_y;
  720.   else
  721.     y = private->ratio * (resize->offset_y + private->old_height - resize->height);
  722.  
  723.   w = private->ratio * private->old_width;
  724.   h = private->ratio * private->old_height;
  725.  
  726.   gdk_window_clear (private->drawing_area->window);
  727.   gtk_draw_shadow (widget->style, widget->window,
  728.            GTK_STATE_NORMAL, GTK_SHADOW_OUT,
  729.            x, y, w, h);
  730.  
  731.   /*  If we're making the size smaller  */
  732.   if (private->old_width > resize->width ||
  733.       private->old_height > resize->height)
  734.     {
  735.       if (private->old_width > resize->width)
  736.     {
  737.       x = private->ratio * (private->old_width - resize->width);
  738.       w = private->ratio * resize->width;
  739.     }
  740.       else
  741.     {
  742.       x = -1;
  743.       w = aw + 2;
  744.     }
  745.       if (private->old_height > resize->height)
  746.     {
  747.       y = private->ratio * (private->old_height - resize->height);
  748.       h = private->ratio * resize->height;
  749.     }
  750.       else
  751.     {
  752.       y = -1;
  753.       h = ah + 2;
  754.     }
  755.  
  756.       gdk_draw_rectangle (private->drawing_area->window,
  757.               widget->style->black_gc, 0,
  758.               x, y, w, h);
  759.     }
  760. }
  761.  
  762. static gint
  763. resize_bound_off_x (Resize *resize,
  764.             gint    off_x)
  765. {
  766.   ResizePrivate *private;
  767.  
  768.   private = (ResizePrivate *) resize->private_part;
  769.  
  770.   if (private->old_width <= resize->width)
  771.     off_x = CLAMP (off_x, 0, (resize->width - private->old_width));
  772.   else
  773.     off_x = CLAMP (off_x, (resize->width - private->old_width), 0);
  774.  
  775.   return off_x;
  776. }
  777.  
  778. static gint
  779. resize_bound_off_y (Resize *resize,
  780.             gint    off_y)
  781. {
  782.   ResizePrivate *private;
  783.  
  784.   private = (ResizePrivate *) resize->private_part;
  785.  
  786.   if (private->old_height <= resize->height)
  787.     off_y = CLAMP (off_y, 0, (resize->height - private->old_height));
  788.   else
  789.     off_y = CLAMP (off_y, (resize->height - private->old_height), 0);
  790.  
  791.   return off_y;
  792. }
  793.  
  794. static void
  795. orig_labels_update (GtkWidget *widget,
  796.             gpointer   data)
  797. {
  798.   Resize        *resize;
  799.   ResizePrivate *private;
  800.   GimpUnit       unit;
  801.   gchar          format_buf[16];
  802.   gchar          buf[32];
  803.  
  804.   static GimpUnit label_unit = GIMP_UNIT_PIXEL;
  805.  
  806.   resize = (Resize *) data;
  807.   private = (ResizePrivate *) resize->private_part;
  808.  
  809.   unit = gimp_size_entry_get_unit (GIMP_SIZE_ENTRY (widget));
  810.  
  811.   if (unit != GIMP_UNIT_PERCENT)
  812.     label_unit = unit;
  813.  
  814.   if (label_unit) /* unit != GIMP_UNIT_PIXEL */
  815.     {
  816.       gdouble unit_factor = gimp_unit_get_factor (label_unit);
  817.   
  818.       g_snprintf (format_buf, sizeof (format_buf), "%%.%df %s",
  819.                   gimp_unit_get_digits (label_unit) + 1,
  820.                   gimp_unit_get_symbol (label_unit));
  821.       g_snprintf (buf, sizeof (buf), format_buf,
  822.                   private->old_width * unit_factor / private->old_res_x);
  823.       gtk_label_set_text (GTK_LABEL (private->orig_width_label), buf);
  824.       g_snprintf (buf, sizeof (buf), format_buf,
  825.                   private->old_height * unit_factor / private->old_res_y);
  826.       gtk_label_set_text (GTK_LABEL (private->orig_height_label), buf);
  827.     }
  828.   else /* unit == GIMP_UNIT_PIXEL */
  829.     {
  830.       g_snprintf (buf, sizeof (buf), "%d", private->old_width);
  831.       gtk_label_set_text (GTK_LABEL (private->orig_width_label), buf);
  832.       g_snprintf (buf, sizeof (buf), "%d", private->old_height);
  833.       gtk_label_set_text (GTK_LABEL (private->orig_height_label), buf);
  834.     }
  835. }
  836.  
  837. static void
  838. unit_update (GtkWidget *widget,
  839.          gpointer   data)
  840. {
  841.   Resize *resize;
  842.  
  843.   resize = (Resize *) data;
  844.   resize->unit = gimp_size_entry_get_unit (GIMP_SIZE_ENTRY (widget));
  845. }
  846.  
  847. static void
  848. offset_update (GtkWidget *widget,
  849.            gpointer   data)
  850. {
  851.   Resize *resize;
  852.   ResizePrivate *private;
  853.   gint offset_x;
  854.   gint offset_y;
  855.  
  856.   resize = (Resize *) data;
  857.   private = (ResizePrivate *) resize->private_part;
  858.  
  859.   offset_x =
  860.     RINT (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (private->offset_se), 0));
  861.   offset_x = resize_bound_off_x (resize, offset_x);
  862.  
  863.   offset_y =
  864.     RINT (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (private->offset_se), 1));
  865.   offset_y = resize_bound_off_y (resize, offset_y);
  866.  
  867.   if ((offset_x != resize->offset_x) ||
  868.       (offset_y != resize->offset_y))
  869.     {
  870.       resize->offset_x = offset_x;
  871.       resize->offset_y = offset_y;
  872.       resize_draw (resize);
  873.     }
  874. }
  875.  
  876. /*
  877.  * Callback function for "Reset" button.
  878.  * Data must be a pointer pointer to a Resize structure.
  879.  */
  880. static void
  881. reset_callback (GtkWidget *widget,
  882.                 gpointer data)
  883. {
  884.   Resize *resize;
  885.   ResizePrivate *private;
  886.  
  887.   resize = (Resize *)data;
  888.   private = (ResizePrivate *)resize->private_part;
  889.  
  890.   /* restore size and ratio settings */
  891.   size_update (resize, private->old_width, private->old_height, 1.0, 1.0);
  892.  
  893.   if ((resize->type == ScaleWidget) && (resize->target == ResizeImage))
  894.     {
  895.       /* restore resolution settings */
  896.       resolution_update (resize, private->old_res_x, private->old_res_y);
  897.     }
  898.  
  899. }
  900.   
  901. static void
  902. size_callback (GtkWidget *widget,
  903.            gpointer   data)
  904. {
  905.   Resize *resize;
  906.   ResizePrivate *private;
  907.   gdouble width;
  908.   gdouble height;
  909.   gdouble ratio_x;
  910.   gdouble ratio_y;
  911.  
  912.   resize  = (Resize *) data;
  913.   private = (ResizePrivate *) resize->private_part;
  914.  
  915.   width  = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (private->size_se), 0);
  916.   height = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (private->size_se), 1);
  917.  
  918.   ratio_x = width  / (gdouble) private->old_width;
  919.   ratio_y = height / (gdouble) private->old_height;
  920.  
  921.   if (gimp_chain_button_get_active (GIMP_CHAIN_BUTTON (private->constrain)))
  922.     {
  923.       if (ratio_x != resize->ratio_x)
  924.     {
  925.       ratio_y = ratio_x;
  926.       height = (gdouble) private->old_height * ratio_y;
  927.       height = CLAMP (height, GIMP_MIN_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE);
  928.     }
  929.       else
  930.     {
  931.       ratio_x = ratio_y;
  932.       width = (gdouble) private->old_width * ratio_x;
  933.       width = CLAMP (width, GIMP_MIN_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE);
  934.     }
  935.     }
  936.  
  937.   size_update (resize, width, height, ratio_x, ratio_y);
  938. }
  939.  
  940. static void
  941. ratio_callback (GtkWidget *widget,
  942.         gpointer   data)
  943. {
  944.   Resize *resize;
  945.   ResizePrivate *private;
  946.   gdouble width;
  947.   gdouble height;
  948.   gdouble ratio_x;
  949.   gdouble ratio_y;
  950.  
  951.   resize  = (Resize *) data;
  952.   private = (ResizePrivate *) resize->private_part;
  953.  
  954.   width  = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (private->size_se), 0);
  955.   height = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (private->size_se), 1);
  956.  
  957.   ratio_x = GTK_ADJUSTMENT (private->ratio_x_adj)->value;
  958.   ratio_y = GTK_ADJUSTMENT (private->ratio_y_adj)->value;
  959.  
  960.   if (gimp_chain_button_get_active (GIMP_CHAIN_BUTTON (private->constrain)))
  961.     {
  962.       if (ratio_x != resize->ratio_x)
  963.     {
  964.       ratio_y = ratio_x;
  965.     }
  966.       else
  967.     {
  968.       ratio_x = ratio_y;
  969.     }
  970.     }
  971.  
  972.   width  = CLAMP (private->old_width * ratio_x,
  973.           GIMP_MIN_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE);
  974.   height = CLAMP (private->old_height * ratio_y,
  975.           GIMP_MIN_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE);
  976.  
  977.   size_update (resize, width, height, ratio_x, ratio_y);
  978. }
  979.  
  980. static void
  981. size_update (Resize *resize,
  982.          double  width,
  983.          double  height,
  984.          double  ratio_x,
  985.          double  ratio_y)
  986. {
  987.   ResizePrivate *private;
  988.  
  989.   private = (ResizePrivate *) resize->private_part;
  990.  
  991.   resize->width = (gint) (width + 0.5);
  992.   resize->height = (gint) (height + 0.5);
  993.  
  994.   resize->ratio_x = ratio_x;
  995.   resize->ratio_y = ratio_y;
  996.  
  997.   gtk_signal_handler_block_by_data (GTK_OBJECT (private->size_se), resize);
  998.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->size_se),
  999.                   0, width);
  1000.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->size_se),
  1001.                   1, height);
  1002.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->size_se), resize);
  1003.  
  1004.   gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_x_adj), resize);
  1005.   gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_y_adj), resize);
  1006.   gtk_adjustment_set_value (GTK_ADJUSTMENT (private->ratio_x_adj), ratio_x);
  1007.   gtk_adjustment_set_value (GTK_ADJUSTMENT (private->ratio_y_adj), ratio_y);
  1008.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_x_adj), resize);
  1009.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_y_adj), resize);
  1010.  
  1011.   if (resize->type == ResizeWidget)
  1012.     {
  1013.       resize->offset_x = resize_bound_off_x (resize, resize->offset_x);
  1014.       resize->offset_y = resize_bound_off_y (resize, resize->offset_y);
  1015.  
  1016.       gimp_size_entry_set_refval_boundaries
  1017.     (GIMP_SIZE_ENTRY (private->offset_se), 0,
  1018.      MIN (0, resize->width - private->old_width),
  1019.      MAX (0, resize->width - private->old_width));
  1020.       gimp_size_entry_set_refval_boundaries
  1021.     (GIMP_SIZE_ENTRY (private->offset_se), 1,
  1022.      MIN (0, resize->height - private->old_height),
  1023.      MAX (0, resize->height - private->old_height));
  1024.  
  1025.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->offset_se),
  1026.                   0, resize->offset_x);
  1027.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->offset_se),
  1028.                   1, resize->offset_y);
  1029.     }
  1030.  
  1031.   if ((resize->type == ScaleWidget) && (resize->target == ResizeImage))
  1032.     {
  1033.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->printsize_se),
  1034.                     resize);
  1035.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->printsize_se),
  1036.                   0, width);
  1037.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->printsize_se),
  1038.                   1, height);
  1039.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->printsize_se),
  1040.                       resize);
  1041.     }
  1042.  
  1043.   resize_draw (resize);
  1044. }
  1045.  
  1046. static void
  1047. printsize_update (GtkWidget *widget,
  1048.           gpointer   data)
  1049. {
  1050.   Resize *resize;
  1051.   ResizePrivate *private;
  1052.   gdouble width;
  1053.   gdouble height;
  1054.   gdouble print_width;
  1055.   gdouble print_height;
  1056.   gdouble res_x;
  1057.   gdouble res_y;
  1058.  
  1059.   resize  = (Resize *) data;
  1060.   private = (ResizePrivate *) resize->private_part;
  1061.  
  1062.   width  = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (private->size_se), 0);
  1063.   height = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (private->size_se), 1);
  1064.  
  1065.   print_width =
  1066.     gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (private->printsize_se), 0);
  1067.   print_height =
  1068.     gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (private->printsize_se), 1);
  1069.  
  1070.   /*  this is tricky: we use the sizes in pixels (which is otherwise
  1071.    *  meaningless for the "print size" widgets) to calculate the new
  1072.    *  resolution.
  1073.    */
  1074.   res_x = CLAMP (resize->resolution_x * width / print_width,
  1075.          GIMP_MIN_RESOLUTION, GIMP_MAX_RESOLUTION);
  1076.   res_y = CLAMP (resize->resolution_y * height / print_height,
  1077.          GIMP_MIN_RESOLUTION, GIMP_MAX_RESOLUTION);
  1078.  
  1079.   if (gimp_chain_button_get_active (GIMP_CHAIN_BUTTON (private->equal_res)))
  1080.     {
  1081.       if (res_x != resize->resolution_x)
  1082.     {
  1083.       res_y = res_x;
  1084.     }
  1085.       else
  1086.     {
  1087.       res_x = res_y;
  1088.     }
  1089.     }
  1090.  
  1091.   resize->resolution_x = res_x;
  1092.   resize->resolution_y = res_y;
  1093.  
  1094.   gtk_signal_handler_block_by_data (GTK_OBJECT (private->resolution_se), resize);
  1095.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->resolution_se),
  1096.                   0, res_x);
  1097.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->resolution_se),
  1098.                   1, res_y);
  1099.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->resolution_se),
  1100.                       resize);
  1101.  
  1102.   gtk_signal_handler_block_by_data (GTK_OBJECT (private->size_se), resize);
  1103.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (private->size_se),
  1104.                   0, res_x, TRUE);
  1105.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (private->size_se),
  1106.                   1, res_y, TRUE);
  1107.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->size_se),
  1108.                   0, width);
  1109.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->size_se),
  1110.                   1, height);
  1111.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->size_se), resize);
  1112.  
  1113.   gtk_signal_handler_block_by_data (GTK_OBJECT (private->printsize_se), resize);
  1114.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (private->printsize_se),
  1115.                   0, res_x, TRUE);
  1116.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (private->printsize_se),
  1117.                   1, res_y, TRUE);
  1118.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->printsize_se),
  1119.                   0, width);
  1120.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->printsize_se),
  1121.                   1, height);
  1122.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->printsize_se),
  1123.                       resize);
  1124. }
  1125.  
  1126. /* Callback for resolution change. */
  1127. static void
  1128. resolution_callback (GtkWidget *widget,
  1129.              gpointer   data)
  1130. {
  1131.   Resize *resize;
  1132.   ResizePrivate *private;
  1133.   gdouble res_x;
  1134.   gdouble res_y;
  1135.   
  1136.   resize  = (Resize *) data;
  1137.   private = (ResizePrivate *) resize->private_part;
  1138.  
  1139.   res_x =
  1140.     gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (private->resolution_se), 0);
  1141.   res_y =
  1142.     gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (private->resolution_se), 1);
  1143.  
  1144.   if (gimp_chain_button_get_active (GIMP_CHAIN_BUTTON (private->equal_res)))
  1145.     {
  1146.       if (res_x != resize->resolution_x)
  1147.     {
  1148.       res_y = res_x;
  1149.     }
  1150.       else
  1151.     {
  1152.       res_x = res_y;
  1153.     }
  1154.     }
  1155.  
  1156.   resolution_update (resize, res_x, res_y);
  1157. }
  1158.  
  1159. /* Update widgets with resolution settings found in given Resize struct. */
  1160. static void
  1161. resolution_update (Resize  *resize,
  1162.            gdouble  res_x,
  1163.            gdouble  res_y)
  1164. {
  1165.   ResizePrivate *private;
  1166.  
  1167.   private = (ResizePrivate *) resize->private_part;
  1168.  
  1169.   resize->resolution_x = res_x;
  1170.   resize->resolution_y = res_y;
  1171.  
  1172.   gtk_signal_handler_block_by_data (GTK_OBJECT (private->resolution_se), resize);
  1173.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->resolution_se),
  1174.                   0, res_x);
  1175.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->resolution_se),
  1176.                   1, res_y);
  1177.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->resolution_se),
  1178.                       resize);
  1179.  
  1180.   gtk_signal_handler_block_by_data (GTK_OBJECT (private->size_se), resize);
  1181.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (private->size_se),
  1182.                   0, res_x, TRUE);
  1183.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (private->size_se),
  1184.                   1, res_y, TRUE);
  1185.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->size_se), resize);
  1186.  
  1187.   gtk_signal_handler_block_by_data (GTK_OBJECT (private->printsize_se), resize);
  1188.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (private->printsize_se),
  1189.                   0, res_x, TRUE);
  1190.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (private->printsize_se),
  1191.                   1, res_y, TRUE);
  1192.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->printsize_se),
  1193.                       resize);
  1194. }
  1195.  
  1196. static gint
  1197. resize_events (GtkWidget *widget,
  1198.            GdkEvent  *event)
  1199. {
  1200.   Resize *resize;
  1201.   ResizePrivate *private;
  1202.   gint dx, dy;
  1203.   gint off_x, off_y;
  1204.  
  1205.   resize  = (Resize *) gtk_object_get_user_data (GTK_OBJECT (widget));
  1206.   private = (ResizePrivate *) resize->private_part;
  1207.  
  1208.   switch (event->type)
  1209.     {
  1210.     case GDK_EXPOSE:
  1211.       resize_draw (resize);
  1212.       break;
  1213.     case GDK_BUTTON_PRESS:
  1214.       gdk_pointer_grab (private->drawing_area->window, FALSE,
  1215.             (GDK_BUTTON1_MOTION_MASK |
  1216.              GDK_BUTTON_RELEASE_MASK),
  1217.             NULL, NULL, event->button.time);
  1218.       private->orig_x  = resize->offset_x;
  1219.       private->orig_y  = resize->offset_y;
  1220.       private->start_x = event->button.x;
  1221.       private->start_y = event->button.y;
  1222.       break;
  1223.     case GDK_MOTION_NOTIFY:
  1224.       /*  X offset  */
  1225.       dx = event->motion.x - private->start_x;
  1226.       off_x = private->orig_x + dx / private->ratio;
  1227.       off_x = resize_bound_off_x (resize, off_x);
  1228.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->offset_se),
  1229.                   0, off_x);
  1230.  
  1231.       /*  Y offset  */
  1232.       dy = event->motion.y - private->start_y;
  1233.       off_y = private->orig_y + dy / private->ratio;
  1234.       off_y = resize_bound_off_y (resize, off_y);
  1235.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (private->offset_se),
  1236.                   1, off_y);
  1237.  
  1238.       gtk_signal_emit_by_name (GTK_OBJECT (private->offset_se), "value_changed",
  1239.                    resize);
  1240.       break;
  1241.     case GDK_BUTTON_RELEASE:
  1242.       gdk_pointer_ungrab (event->button.time);
  1243.       break;
  1244.     default:
  1245.       break;
  1246.     }
  1247.  
  1248.   return FALSE;
  1249. }
  1250.  
  1251. /*** Resize sanity checks ***/
  1252.  
  1253. void
  1254. resize_scale_implement (ImageResize *image_scale)
  1255. {
  1256.   GImage   *gimage        = NULL;
  1257.   gboolean  rulers_flush  = FALSE;
  1258.   gboolean  display_flush = FALSE;  /* this is a bit ugly: 
  1259.                        we hijack the flush variable 
  1260.                        to check if an undo_group was 
  1261.                        already started */
  1262.  
  1263.   g_assert (image_scale != NULL);
  1264.   gimage = image_scale->gimage;
  1265.   g_assert (gimage != NULL);
  1266.  
  1267.   if (image_scale->resize->resolution_x != gimage->xresolution ||
  1268.       image_scale->resize->resolution_y != gimage->yresolution)
  1269.     {
  1270.       undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
  1271.       
  1272.       gimage_set_resolution (gimage,
  1273.                  image_scale->resize->resolution_x,
  1274.                  image_scale->resize->resolution_y);
  1275.  
  1276.       rulers_flush = TRUE;
  1277.       display_flush = TRUE;
  1278.     }
  1279.  
  1280.   if (image_scale->resize->unit != gimage->unit)
  1281.     {
  1282.       if (!display_flush)
  1283.     undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
  1284.  
  1285.       gimage_set_unit (gimage, image_scale->resize->unit);
  1286.       gdisplays_setup_scale (gimage);
  1287.       gdisplays_resize_cursor_label (gimage);
  1288.  
  1289.       rulers_flush = TRUE;
  1290.       display_flush = TRUE;
  1291.     }
  1292.  
  1293.   if (image_scale->resize->width != gimage->width ||
  1294.       image_scale->resize->height != gimage->height)
  1295.     {
  1296.       if (image_scale->resize->width > 0 &&
  1297.       image_scale->resize->height > 0) 
  1298.     {
  1299.       if (!display_flush)
  1300.         undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
  1301.  
  1302.       gimage_scale (gimage,
  1303.             image_scale->resize->width,
  1304.             image_scale->resize->height);
  1305.  
  1306.       display_flush = TRUE;
  1307.     }
  1308.       else
  1309.     {
  1310.       g_message (_("Scale Error: Both width and height must be "
  1311.                "greater than zero."));
  1312.       return;
  1313.     }
  1314.     }
  1315.  
  1316.   if (rulers_flush)
  1317.     {
  1318.       gdisplays_setup_scale (gimage);
  1319.       gdisplays_resize_cursor_label (gimage);
  1320.     }
  1321.       
  1322.   if (display_flush)
  1323.     {
  1324.       undo_push_group_end (gimage);
  1325.       gdisplays_flush ();
  1326.     }
  1327. }
  1328.  
  1329. static void
  1330. resize_scale_warn_callback (GtkWidget *widget,
  1331.                 gboolean   do_scale,
  1332.                 gpointer   data)
  1333. {
  1334.   ImageResize *image_scale = NULL;
  1335.   GImage      *gimage      = NULL;
  1336.  
  1337.   g_assert (data != NULL);
  1338.   image_scale = (ImageResize *) data;
  1339.   gimage      = image_scale->gimage;
  1340.   g_assert (gimage != NULL);
  1341.  
  1342.   if (do_scale == TRUE) /* User doesn't mind losing layers... */
  1343.     {
  1344.       resize_scale_implement (image_scale);
  1345.       gtk_widget_destroy (image_scale->resize->resize_shell);
  1346.     }
  1347.   else
  1348.     {
  1349.       gtk_widget_set_sensitive (image_scale->resize->resize_shell, TRUE);
  1350.     }
  1351. }
  1352.  
  1353. gboolean 
  1354. resize_check_layer_scaling (ImageResize *image_scale)
  1355. {
  1356.   /* Inventory the layer list in gimage and return TRUE if, after
  1357.    * scaling, they all retain positive x and y pixel dimensions.
  1358.    * Otherwise, put up a modal boolean dialog box and ask the user if
  1359.    * she wishes to proceed. Return FALSE in the dialog case; the dialog box
  1360.    * callback will complete the job if the user really wants to
  1361.    * proceed. <02/22/2000 gosgood@idt.net>
  1362.    */
  1363.  
  1364.   gboolean   success = FALSE;
  1365.   GImage    *gimage  = NULL;
  1366.   GSList    *list    = NULL;
  1367.   Layer     *layer   = NULL;
  1368.   GtkWidget *dialog  = NULL;
  1369.  
  1370.   g_assert (image_scale != NULL);
  1371.  
  1372.   if (NULL != (gimage = image_scale->gimage))
  1373.     {
  1374.       /* Step through layers; test scaled dimensions. */
  1375.  
  1376.       success = TRUE;
  1377.       list    = gimage->layers;
  1378.       while (list && success == TRUE)
  1379.     {
  1380.       layer   = (Layer *)list->data;
  1381.       success = layer_check_scaling (layer, 
  1382.                      image_scale->resize->width,
  1383.                      image_scale->resize->height);
  1384.       list   = g_slist_next (list);
  1385.       
  1386.     }
  1387.       /* Warn user on failure */
  1388.       if (success == FALSE)
  1389.     {
  1390.       dialog =
  1391.         gimp_query_boolean_box (_("Layer Too Small"),
  1392.                     gimp_standard_help_func,
  1393.                     "dialogs/scale_layer_warn.html",
  1394.                     FALSE,
  1395.                     _("The chosen image size will shrink\n"
  1396.                       "some layers completely away.\n"
  1397.                       "Is this what you want?"),
  1398.                     _("OK"), _("Cancel"),
  1399.                     GTK_OBJECT (image_scale->resize->resize_shell),
  1400.                     "destroy",
  1401.                     resize_scale_warn_callback,
  1402.                     image_scale);
  1403.       gtk_widget_show (dialog);
  1404.     }
  1405.     }
  1406.   return success;
  1407. }
  1408.