home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / gap / resize.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-10  |  26.6 KB  |  826 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. #include <math.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <gtk/gtk.h>
  22. #include "config.h"
  23. #include "libgimp/stdplugins-intl.h"
  24. #include "resize.h"
  25.  
  26. #define EVENT_MASK  GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK
  27. #define DRAWING_AREA_SIZE 200
  28. #define TEXT_WIDTH 35
  29.  
  30.  
  31. typedef struct _ResizePrivate ResizePrivate;
  32.  
  33. struct _ResizePrivate
  34. {
  35.   GtkWidget *width_text;
  36.   GtkWidget *height_text;
  37.   GtkWidget *ratio_x_text;
  38.   GtkWidget *ratio_y_text;
  39.   GtkWidget *off_x_text;
  40.   GtkWidget *off_y_text;
  41.   GtkWidget *drawing_area;
  42.  
  43.   double ratio;
  44.   int constrain;
  45.   int old_width, old_height;
  46.   int area_width, area_height;
  47.   int start_x, start_y;
  48.   int orig_x, orig_y;
  49. };
  50.  
  51. static void resize_draw (Resize *);
  52. static int  resize_bound_off_x (Resize *, int);
  53. static int  resize_bound_off_y (Resize *, int);
  54. static void off_x_update (GtkWidget *w, gpointer data);
  55. static void off_y_update (GtkWidget *w, gpointer data);
  56. static void width_update (GtkWidget *w, gpointer data);
  57. static void height_update (GtkWidget *w, gpointer data);
  58. static void ratio_x_update (GtkWidget *w, gpointer data);
  59. static void ratio_y_update (GtkWidget *w, gpointer data);
  60. static void constrain_update (GtkWidget *w, gpointer data);
  61. static gint resize_events (GtkWidget *area, GdkEvent *event);
  62.  
  63.  
  64. Resize *
  65. resize_widget_new (ResizeType type,
  66.            int        width,
  67.            int        height)
  68. {
  69.   Resize *resize;
  70.   ResizePrivate *private;
  71.   GtkWidget *vbox;
  72.   GtkWidget *hbox;
  73.   GtkWidget *label;
  74.   GtkWidget *frame;
  75.   GtkWidget *constrain;
  76.   GtkWidget *table;
  77.   char size[12];
  78.   char ratio_text[12];
  79.  
  80.   table = NULL;
  81.  
  82.   resize = g_new (Resize, 1);
  83.   private = g_new (ResizePrivate, 1);
  84.   resize->type = type;
  85.   resize->private_part = private;
  86.   resize->width = width;
  87.   resize->height = height;
  88.   resize->ratio_x = 1.0;
  89.   resize->ratio_y = 1.0;
  90.   resize->off_x = 0;
  91.   resize->off_y = 0;
  92.   private->old_width = width;
  93.   private->old_height = height;
  94.   private->constrain = TRUE;
  95.  
  96.   /*  Get the image width and height variables, based on the gimage  */
  97.   if (width > height)
  98.     private->ratio = (double) DRAWING_AREA_SIZE / (double) width;
  99.   else
  100.     private->ratio = (double) DRAWING_AREA_SIZE / (double) height;
  101.   private->area_width = (int) (private->ratio * width);
  102.   private->area_height = (int) (private->ratio * height);
  103.  
  104.   switch (type)
  105.     {
  106.     case ScaleWidget:
  107.       resize->resize_widget = gtk_frame_new ( _("Scale"));
  108.       table = gtk_table_new (4, 2, TRUE);
  109.       break;
  110.     case ResizeWidget:
  111.       resize->resize_widget = gtk_frame_new ( _("Resize"));
  112.       table = gtk_table_new (6, 2, TRUE);
  113.       break;
  114.     }
  115.   gtk_frame_set_shadow_type (GTK_FRAME (resize->resize_widget), GTK_SHADOW_ETCHED_IN);
  116.  
  117.   /*  the main vbox  */
  118.   vbox = gtk_vbox_new (FALSE, 1);
  119.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
  120.   gtk_container_add (GTK_CONTAINER (resize->resize_widget), vbox);
  121.  
  122.   gtk_container_set_border_width (GTK_CONTAINER (table), 2);
  123.   gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
  124.  
  125.   /*  the width label and entry  */
  126.   g_snprintf (size, sizeof(size), "%d", width);
  127.   label = gtk_label_new ( _("New width:"));
  128.   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  129.   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
  130.             GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  131.   gtk_widget_show (label);
  132.   private->width_text = gtk_entry_new ();
  133.   gtk_table_attach (GTK_TABLE (table), private->width_text, 1, 2, 0, 1,
  134.             GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  135.   gtk_widget_set_usize (private->width_text, TEXT_WIDTH, 25);
  136.   gtk_entry_set_text (GTK_ENTRY (private->width_text), size);
  137.   gtk_signal_connect (GTK_OBJECT (private->width_text), "changed",
  138.               (GtkSignalFunc) width_update,
  139.               resize);
  140.   gtk_widget_show (private->width_text);
  141.  
  142.   /*  the height label and entry  */
  143.   g_snprintf (size, sizeof(size), "%d", height);
  144.   label = gtk_label_new ( _("New height:"));
  145.   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  146.   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
  147.             GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  148.   gtk_widget_show (label);
  149.   private->height_text = gtk_entry_new ();
  150.   gtk_table_attach (GTK_TABLE (table), private->height_text, 1, 2, 1, 2,
  151.             GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  152.   gtk_widget_set_usize (private->height_text, TEXT_WIDTH, 25);
  153.   gtk_entry_set_text (GTK_ENTRY (private->height_text), size);
  154.   gtk_signal_connect (GTK_OBJECT (private->height_text), "changed",
  155.               (GtkSignalFunc) height_update,
  156.               resize);
  157.   gtk_widget_show (private->height_text);
  158.  
  159.   /*  the x scale ratio label and entry  */
  160.   g_snprintf (ratio_text, sizeof(ratio_text), "%0.4f", resize->ratio_x);
  161.   label = gtk_label_new ( _("X ratio:"));
  162.   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  163.   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
  164.             GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  165.   gtk_widget_show (label);
  166.   private->ratio_x_text = gtk_entry_new ();
  167.   gtk_table_attach (GTK_TABLE (table), private->ratio_x_text, 1, 2, 2, 3,
  168.             GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  169.   gtk_widget_set_usize (private->ratio_x_text, TEXT_WIDTH, 25);
  170.   gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
  171.   gtk_signal_connect (GTK_OBJECT (private->ratio_x_text), "changed",
  172.               (GtkSignalFunc) ratio_x_update,
  173.               resize);
  174.   gtk_widget_show (private->ratio_x_text);
  175.  
  176.   /*  the y scale ratio label and entry  */
  177.   g_snprintf (ratio_text, sizeof(ratio_text), "%0.4f", resize->ratio_y);
  178.   label = gtk_label_new ( _("Y ratio:"));
  179.   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  180.   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
  181.             GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  182.   gtk_widget_show (label);
  183.   private->ratio_y_text = gtk_entry_new ();
  184.   gtk_table_attach (GTK_TABLE (table), private->ratio_y_text, 1, 2, 3, 4,
  185.             GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  186.   gtk_widget_set_usize (private->ratio_y_text, TEXT_WIDTH, 25);
  187.   gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
  188.   gtk_signal_connect (GTK_OBJECT (private->ratio_y_text), "changed",
  189.               (GtkSignalFunc) ratio_y_update,
  190.               resize);
  191.   gtk_widget_show (private->ratio_y_text);
  192.  
  193.   if (type == ResizeWidget)
  194.     {
  195.       /*  the off_x label and entry  */
  196.       g_snprintf (size, sizeof(size), "%d", 0);
  197.       label = gtk_label_new ( _("X Offset:"));
  198.       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  199.       gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5,
  200.             GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  201.       gtk_widget_show (label);
  202.       private->off_x_text = gtk_entry_new ();
  203.       gtk_table_attach (GTK_TABLE (table), private->off_x_text, 1, 2, 4, 5,
  204.             GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  205.       gtk_widget_set_usize (private->off_x_text, TEXT_WIDTH, 25);
  206.       gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
  207.       gtk_signal_connect (GTK_OBJECT (private->off_x_text), "changed",
  208.               (GtkSignalFunc) off_x_update,
  209.               resize);
  210.       gtk_widget_show (private->off_x_text);
  211.  
  212.       /*  the off_y label and entry  */
  213.       g_snprintf (size, sizeof(size), "%d", 0);
  214.       label = gtk_label_new ( _("Y Offset:"));
  215.       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  216.       gtk_table_attach (GTK_TABLE (table), label, 0, 1, 5, 6,
  217.             GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  218.       gtk_widget_show (label);
  219.       private->off_y_text = gtk_entry_new ();
  220.       gtk_table_attach (GTK_TABLE (table), private->off_y_text, 1, 2, 5, 6,
  221.             GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  222.       gtk_widget_set_usize (private->off_y_text, TEXT_WIDTH, 25);
  223.       gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
  224.       gtk_signal_connect (GTK_OBJECT (private->off_y_text), "changed",
  225.               (GtkSignalFunc) off_y_update,
  226.               resize);
  227.       gtk_widget_show (private->off_y_text);
  228.     }
  229.  
  230.   /*  the constrain toggle button  */
  231.   constrain = gtk_check_button_new_with_label ( _("Constrain Ratio"));
  232.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (constrain), private->constrain);
  233.   gtk_box_pack_start (GTK_BOX (vbox), constrain, FALSE, FALSE, 0);
  234.   gtk_signal_connect (GTK_OBJECT (constrain), "toggled",
  235.               (GtkSignalFunc) constrain_update,
  236.               resize);
  237.   gtk_widget_show (constrain);
  238.  
  239.   if (type == ResizeWidget)
  240.     {
  241.       /*  frame to hold drawing area  */
  242.       hbox = gtk_hbox_new (FALSE, 1);
  243.       gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 0);
  244.       frame = gtk_frame_new (NULL);
  245.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  246.       gtk_container_set_border_width (GTK_CONTAINER (frame), 2);
  247.       gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, FALSE, 0);
  248.       private->drawing_area = gtk_drawing_area_new ();
  249.       gtk_drawing_area_size (GTK_DRAWING_AREA (private->drawing_area),
  250.                  private->area_width, private->area_height);
  251.       gtk_widget_set_events (private->drawing_area, EVENT_MASK);
  252.       gtk_signal_connect (GTK_OBJECT (private->drawing_area), "event",
  253.               (GtkSignalFunc) resize_events,
  254.               NULL);
  255.       gtk_object_set_user_data (GTK_OBJECT (private->drawing_area), resize);
  256.       gtk_container_add (GTK_CONTAINER (frame), private->drawing_area);
  257.       gtk_widget_show (private->drawing_area);
  258.       gtk_widget_show (frame);
  259.       gtk_widget_show (hbox);
  260.     }
  261.  
  262.   gtk_widget_show (table);
  263.   gtk_widget_show (vbox);
  264.  
  265.   return resize;
  266. }
  267.  
  268. void
  269. resize_widget_free (Resize *resize)
  270. {
  271.   g_free (resize->private_part);
  272.   g_free (resize);
  273. }
  274.  
  275. static void
  276. resize_draw (Resize *resize)
  277. {
  278.   GtkWidget *widget;
  279.   ResizePrivate *private;
  280.   int aw, ah;
  281.   int x, y;
  282.   int w, h;
  283.  
  284.   /*  Only need to draw if it's a resize widget  */
  285.   if (resize->type != ResizeWidget)
  286.     return;
  287.  
  288.   private = (ResizePrivate *) resize->private_part;
  289.   widget = private->drawing_area;
  290.  
  291.   /*  If we're making the size larger  */
  292.   if (private->old_width <= resize->width)
  293.     w = resize->width;
  294.   /*  otherwise, if we're making the size smaller  */
  295.   else
  296.     w = private->old_width * 2 - resize->width;
  297.   /*  If we're making the size larger  */
  298.   if (private->old_height <= resize->height)
  299.     h = resize->height;
  300.   /*  otherwise, if we're making the size smaller  */
  301.   else
  302.     h = private->old_height * 2 - resize->height;
  303.  
  304.   if (w > h)
  305.     private->ratio = (double) DRAWING_AREA_SIZE / (double) w;
  306.   else
  307.     private->ratio = (double) DRAWING_AREA_SIZE / (double) h;
  308.  
  309.   aw = (int) (private->ratio * w);
  310.   ah = (int) (private->ratio * h);
  311.  
  312.   if (aw != private->area_width || ah != private->area_height)
  313.     {
  314.       private->area_width = aw;
  315.       private->area_height = ah;
  316.       gtk_widget_set_usize (private->drawing_area, aw, ah);
  317.     }
  318.  
  319.   if (private->old_width <= resize->width)
  320.     x = private->ratio * resize->off_x;
  321.   else
  322.     x = private->ratio * (resize->off_x + private->old_width - resize->width);
  323.   if (private->old_height <= resize->height)
  324.     y = private->ratio * resize->off_y;
  325.   else
  326.     y = private->ratio * (resize->off_y + private->old_height - resize->height);
  327.  
  328.   w = private->ratio * private->old_width;
  329.   h = private->ratio * private->old_height;
  330.  
  331.   gdk_window_clear (private->drawing_area->window);
  332.   gtk_draw_shadow (widget->style, widget->window,
  333.            GTK_STATE_NORMAL, GTK_SHADOW_OUT,
  334.            x, y, w, h);
  335.  
  336.   /*  If we're making the size smaller  */
  337.   if (private->old_width > resize->width ||
  338.       private->old_height > resize->height)
  339.     {
  340.       if (private->old_width > resize->width)
  341.     {
  342.       x = private->ratio * (private->old_width - resize->width);
  343.       w = private->ratio * resize->width;
  344.     }
  345.       else
  346.     {
  347.       x = -1;
  348.       w = aw + 2;
  349.     }
  350.       if (private->old_height > resize->height)
  351.     {
  352.       y = private->ratio * (private->old_height - resize->height);
  353.       h = private->ratio * resize->height;
  354.     }
  355.       else
  356.     {
  357.       y = -1;
  358.       h = ah + 2;
  359.     }
  360.  
  361.       gdk_draw_rectangle (private->drawing_area->window,
  362.               widget->style->black_gc, 0,
  363.               x, y, w, h);
  364.     }
  365.  
  366. }
  367.  
  368. static int
  369. resize_bound_off_x (Resize *resize,
  370.             int     off_x)
  371. {
  372.   ResizePrivate *private;
  373.  
  374.   private = (ResizePrivate *) resize->private_part;
  375.  
  376.   if (private->old_width <= resize->width)
  377.     off_x = CLAMP (off_x, 0, (resize->width - private->old_width));
  378.   else
  379.     off_x = CLAMP (off_x, (resize->width - private->old_width), 0);
  380.  
  381.   return off_x;
  382. }
  383.  
  384. static int
  385. resize_bound_off_y (Resize *resize,
  386.             int     off_y)
  387. {
  388.   ResizePrivate *private;
  389.  
  390.   private = (ResizePrivate *) resize->private_part;
  391.  
  392.   if (private->old_height <= resize->height)
  393.     off_y = CLAMP (off_y, 0, (resize->height - private->old_height));
  394.   else
  395.     off_y = CLAMP (off_y, (resize->height - private->old_height), 0);
  396.  
  397.   return off_y;
  398. }
  399.  
  400. static void
  401. constrain_update (GtkWidget *w,
  402.           gpointer   data)
  403. {
  404.   Resize *resize;
  405.   ResizePrivate *private;
  406.  
  407.   resize = (Resize *) data;
  408.   private = (ResizePrivate *) resize->private_part;
  409.  
  410.   if (GTK_TOGGLE_BUTTON (w)->active)
  411.     private->constrain = TRUE;
  412.   else
  413.     private->constrain = FALSE;
  414. }
  415.  
  416. static void
  417. off_x_update (GtkWidget *w,
  418.           gpointer   data)
  419. {
  420.   Resize *resize;
  421.   ResizePrivate *private;
  422.   char *str;
  423.   int offset;
  424.  
  425.   resize = (Resize *) data;
  426.   private = (ResizePrivate *) resize->private_part;
  427.   str = gtk_entry_get_text (GTK_ENTRY (w));
  428.  
  429.   offset = atoi (str);
  430.   offset = resize_bound_off_x (resize, offset);
  431.  
  432.   if (offset != resize->off_x)
  433.     {
  434.       resize->off_x = offset;
  435.       resize_draw (resize);
  436.     }
  437. }
  438.  
  439. static void
  440. off_y_update (GtkWidget *w,
  441.           gpointer   data)
  442. {
  443.   Resize *resize;
  444.   ResizePrivate *private;
  445.   char *str;
  446.   int offset;
  447.  
  448.   resize = (Resize *) data;
  449.   private = (ResizePrivate *) resize->private_part;
  450.   str = gtk_entry_get_text (GTK_ENTRY (w));
  451.  
  452.   offset = atoi (str);
  453.   offset = resize_bound_off_y (resize, offset);
  454.  
  455.   if (offset != resize->off_y)
  456.     {
  457.       resize->off_y = offset;
  458.       resize_draw (resize);
  459.     }
  460. }
  461.  
  462. static void
  463. width_update (GtkWidget *w,
  464.           gpointer   data)
  465. {
  466.   Resize *resize;
  467.   ResizePrivate *private;
  468.   char *str;
  469.   double ratio;
  470.   int new_height;
  471.   char size[12];
  472.   char ratio_text[12];
  473.  
  474.   resize = (Resize *) data;
  475.   private = (ResizePrivate *) resize->private_part;
  476.   str = gtk_entry_get_text (GTK_ENTRY (w));
  477.  
  478.   resize->width = atoi (str);
  479.  
  480.   ratio = (double) resize->width / (double) private->old_width;
  481.   resize->ratio_x = ratio;
  482.   g_snprintf (ratio_text, sizeof(ratio_text), "%0.4f", ratio);  
  483.  
  484.   gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_x_text), data);
  485.   gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
  486.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_x_text), data);
  487.  
  488.   if (resize->type == ResizeWidget)
  489.     {
  490.       resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
  491.       g_snprintf (size, sizeof(size), "%d", resize->off_x);
  492.  
  493.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_x_text), data);
  494.       gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
  495.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_x_text), data);
  496.     }
  497.  
  498.   if (private->constrain && resize->width != 0)
  499.     {
  500.       private->constrain = FALSE;
  501.       new_height = (int) (private->old_height * ratio);
  502.       if (new_height == 0) new_height = 1;
  503.  
  504.       if (new_height != resize->height)
  505.     {
  506.       resize->height = new_height;
  507.       g_snprintf (size, sizeof(size), "%d", resize->height);
  508.  
  509.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->height_text), data);
  510.       gtk_entry_set_text (GTK_ENTRY (private->height_text), size);
  511.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->height_text), data);
  512.  
  513.       resize->ratio_y = ratio;
  514.  
  515.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_y_text), data);
  516.       gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
  517.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_y_text), data);
  518.  
  519.       if (resize->type == ResizeWidget)
  520.         {
  521.           resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
  522.           g_snprintf (size, sizeof(size), "%d", resize->off_y);
  523.  
  524.           gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_y_text), data);
  525.           gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
  526.           gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_y_text), data);
  527.         }
  528.     }
  529.  
  530.       private->constrain = TRUE;
  531.     }
  532.  
  533.   resize_draw (resize);
  534. }
  535.  
  536. static void
  537. height_update (GtkWidget *w,
  538.            gpointer   data)
  539. {
  540.   Resize *resize;
  541.   ResizePrivate *private;
  542.   char *str;
  543.   double ratio;
  544.   int new_width;
  545.   char size[12];
  546.   char ratio_text[12];
  547.  
  548.   resize = (Resize *) data;
  549.   private = (ResizePrivate *) resize->private_part;
  550.   str = gtk_entry_get_text (GTK_ENTRY (w));
  551.  
  552.   resize->height = atoi (str);
  553.  
  554.   ratio = (double) resize->height / (double) private->old_height;
  555.   resize->ratio_y = ratio;
  556.   g_snprintf (ratio_text, sizeof(ratio_text), "%0.4f", ratio);
  557.  
  558.   gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_y_text), data);
  559.   gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
  560.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_y_text), data);
  561.   if (resize->type == ResizeWidget)
  562.     {
  563.       resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
  564.       g_snprintf (size, sizeof(size), "%d", resize->off_y);
  565.  
  566.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_y_text), data);
  567.       gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
  568.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_y_text), data);
  569.     }
  570.  
  571.   if (private->constrain && resize->height != 0)
  572.     {
  573.       private->constrain = FALSE;
  574.       ratio = (double) resize->height / (double) private->old_height;
  575.       new_width = (int) (private->old_width * ratio);
  576.       if (new_width == 0) new_width = 1;
  577.  
  578.       if (new_width != resize->width)
  579.     {
  580.       resize->width = new_width;
  581.       g_snprintf (size, sizeof(size), "%d", resize->width);
  582.  
  583.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->width_text), data);
  584.       gtk_entry_set_text (GTK_ENTRY (private->width_text), size);
  585.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->width_text), data);
  586.       
  587.       resize->ratio_x = ratio;
  588.  
  589.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_x_text), data);
  590.       gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
  591.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_x_text), data);
  592.  
  593.       if (resize->type == ResizeWidget)
  594.         {
  595.           resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
  596.           g_snprintf (size, sizeof(size), "%d", resize->off_x);
  597.  
  598.           gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_x_text), data);
  599.           gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
  600.           gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_x_text), data);
  601.         }
  602.     }
  603.  
  604.       private->constrain = TRUE;
  605.     }
  606.  
  607.   resize_draw (resize);
  608. }
  609.  
  610. static void
  611. ratio_x_update (GtkWidget *w,
  612.         gpointer   data)
  613. {
  614.   Resize *resize;
  615.   ResizePrivate *private;
  616.   char *str;
  617.   int new_width;
  618.   int new_height;
  619.   char size[12];
  620.   char ratio_text[12];
  621.   
  622.   resize = (Resize *) data;
  623.   private = (ResizePrivate *) resize->private_part;
  624.   str = gtk_entry_get_text (GTK_ENTRY (w));
  625.  
  626.   resize->ratio_x = atof (str);
  627.  
  628.   new_width = (int) ((double) private->old_width * resize->ratio_x);
  629.  
  630.   if (new_width != resize->width)
  631.     {
  632.       resize->width = new_width;
  633.       g_snprintf (size, sizeof(size), "%d", new_width);
  634.  
  635.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->width_text), data);
  636.       gtk_entry_set_text (GTK_ENTRY (private->width_text), size);
  637.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->width_text), data);
  638.  
  639.       if (resize->type == ResizeWidget)
  640.     {
  641.       resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
  642.       g_snprintf (size, sizeof(size), "%d", resize->off_x);
  643.       
  644.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_x_text), data);
  645.       gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
  646.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_x_text), data);
  647.     }
  648.     }
  649.  
  650.   if (private->constrain && resize->width != 0)
  651.     {
  652.       private->constrain = FALSE;
  653.  
  654.       resize->ratio_y = resize->ratio_x;
  655.  
  656.       new_height = (int) (private->old_height * resize->ratio_y);
  657.       if (new_height == 0) new_height = 1;
  658.  
  659.       if (new_height != resize->height)
  660.     {
  661.       resize->height = new_height;
  662.  
  663.       g_snprintf (size, sizeof(size), "%d", resize->height);
  664.  
  665.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->height_text), data);
  666.       gtk_entry_set_text (GTK_ENTRY (private->height_text), size);
  667.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->height_text), data);
  668.       
  669.       g_snprintf (ratio_text, sizeof(ratio_text), "%0.4f", resize->ratio_y);  
  670.       
  671.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_y_text), data);
  672.       gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
  673.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_y_text), data);
  674.  
  675.       if (resize->type == ResizeWidget)
  676.         {
  677.           resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
  678.           g_snprintf (size, sizeof(size), "%d", resize->off_y);
  679.  
  680.           gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_y_text), data);
  681.           gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
  682.           gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_y_text), data);
  683.         }
  684.     }
  685.  
  686.       private->constrain = TRUE;
  687.     }
  688.  
  689.   resize_draw (resize);
  690. }
  691.  
  692. static void
  693. ratio_y_update (GtkWidget *w,
  694.         gpointer   data)
  695. {
  696.   Resize *resize;
  697.   ResizePrivate *private;
  698.   char *str;
  699.   int new_width;
  700.   int new_height;
  701.   char size[12];
  702.   char ratio_text[12];
  703.   
  704.   resize = (Resize *) data;
  705.   private = (ResizePrivate *) resize->private_part;
  706.   str = gtk_entry_get_text (GTK_ENTRY (w));
  707.  
  708.   resize->ratio_y = atof (str);
  709.  
  710.   new_height = (int) ((double) private->old_height * resize->ratio_y);
  711.  
  712.   if (new_height != resize->height)
  713.     {
  714.       resize->height = new_height;
  715.       g_snprintf (size, sizeof(size), "%d", new_height);
  716.  
  717.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->height_text), data);
  718.       gtk_entry_set_text (GTK_ENTRY (private->height_text), size);
  719.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->height_text), data);
  720.  
  721.       if (resize->type == ResizeWidget)
  722.     {
  723.       resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
  724.       g_snprintf (size, sizeof(size), "%d", resize->off_y);
  725.       
  726.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_y_text), data);
  727.       gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
  728.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_y_text), data);
  729.     }
  730.     }
  731.  
  732.   if (private->constrain && resize->height != 0)
  733.     {
  734.       private->constrain = FALSE;
  735.  
  736.       resize->ratio_x = resize->ratio_y;
  737.  
  738.       new_width = (int) (private->old_width * resize->ratio_x);
  739.       if (new_width == 0) new_width = 1;
  740.  
  741.       if (new_width != resize->width)
  742.     {
  743.       resize->width = new_width;
  744.  
  745.       g_snprintf (size, sizeof(size), "%d", resize->width);
  746.  
  747.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->width_text), data);
  748.       gtk_entry_set_text (GTK_ENTRY (private->width_text), size);
  749.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->width_text), data);
  750.       
  751.       g_snprintf (ratio_text, sizeof(ratio_text), "%0.4f", resize->ratio_x);  
  752.       
  753.       gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_x_text), data);
  754.       gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
  755.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_x_text), data);
  756.  
  757.       if (resize->type == ResizeWidget)
  758.         {
  759.           resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
  760.           g_snprintf (size, sizeof(size), "%d", resize->off_x);
  761.  
  762.           gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_x_text), data);
  763.           gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
  764.           gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_x_text), data);
  765.         }
  766.     }
  767.  
  768.       private->constrain = TRUE;
  769.     }
  770.  
  771.   resize_draw (resize);
  772. }
  773.  
  774. static gint
  775. resize_events (GtkWidget *widget,
  776.            GdkEvent  *event)
  777. {
  778.   Resize *resize;
  779.   ResizePrivate *private;
  780.   int dx, dy;
  781.   int off_x, off_y;
  782.   char size[12];
  783.  
  784.   resize = (Resize *) gtk_object_get_user_data (GTK_OBJECT (widget));
  785.   private = (ResizePrivate *) resize->private_part;
  786.  
  787.   switch (event->type)
  788.     {
  789.     case GDK_EXPOSE:
  790.       resize_draw (resize);
  791.       break;
  792.     case GDK_BUTTON_PRESS:
  793.       gdk_pointer_grab (private->drawing_area->window, FALSE,
  794.             (GDK_BUTTON1_MOTION_MASK |
  795.              GDK_BUTTON_RELEASE_MASK),
  796.             NULL, NULL, event->button.time);
  797.       private->orig_x = resize->off_x;
  798.       private->orig_y = resize->off_y;
  799.       private->start_x = event->button.x;
  800.       private->start_y = event->button.y;
  801.       break;
  802.     case GDK_MOTION_NOTIFY:
  803.       /*  X offset  */
  804.       dx = event->motion.x - private->start_x;
  805.       off_x = private->orig_x + dx / private->ratio;
  806.       off_x = resize_bound_off_x (resize, off_x);
  807.       g_snprintf (size, sizeof(size), "%d", off_x);
  808.       gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
  809.  
  810.       /*  Y offset  */
  811.       dy = event->motion.y - private->start_y;
  812.       off_y = private->orig_y + dy / private->ratio;
  813.       off_y = resize_bound_off_y (resize, off_y);
  814.       g_snprintf (size, sizeof(size), "%d", off_y);
  815.       gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
  816.       break;
  817.     case GDK_BUTTON_RELEASE:
  818.       gdk_pointer_ungrab (event->button.time);
  819.       break;
  820.     default:
  821.       break;
  822.     }
  823.  
  824.   return FALSE;
  825. }
  826.