home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / rotate_tool.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  11.6 KB  |  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 <glib.h>
  22.  
  23. #include "apptypes.h"
  24.  
  25. #include "appenv.h"
  26. #include "drawable.h"
  27. #include "gdisplay.h"
  28. #include "gimage_mask.h"
  29. #include "info_dialog.h"
  30. #include "rotate_tool.h"
  31. #include "selection.h"
  32. #include "transform_tool.h"
  33. #include "undo.h"
  34.  
  35. #include "tile_manager_pvt.h"
  36.  
  37. #include "libgimp/gimpsizeentry.h"
  38. #include "libgimp/gimpintl.h"
  39. #include "libgimp/gimpmath.h"
  40.  
  41. /*  index into trans_info array  */
  42. #define ANGLE        0
  43. #define REAL_ANGLE   1
  44. #define CENTER_X     2
  45. #define CENTER_Y     3
  46.  
  47. #define EPSILON      0.018  /*  ~ 1 degree  */
  48. #define FIFTEEN_DEG  (G_PI / 12.0)
  49.  
  50. /*  variables local to this file  */
  51. static gdouble    angle_val;
  52. static gdouble    center_vals[2];
  53.  
  54. /*  needed for size update  */
  55. static GtkWidget *sizeentry;
  56.  
  57. /*  forward function declarations  */
  58. static void   rotate_tool_recalc  (Tool *, void *);
  59. static void   rotate_tool_motion  (Tool *, void *);
  60. static void   rotate_info_update  (Tool *);
  61.  
  62. /*  callback functions for the info dialog sizeentries  */
  63. static void   rotate_angle_changed  (GtkWidget *entry, gpointer data);
  64. static void   rotate_center_changed (GtkWidget *entry, gpointer data);
  65.  
  66. TileManager *
  67. rotate_tool_transform (Tool           *tool,
  68.                gpointer        gdisp_ptr,
  69.                TransformState  state)
  70. {
  71.   TransformCore *transform_core;
  72.   GDisplay      *gdisp;
  73.   GtkWidget     *widget;
  74.   GtkWidget     *spinbutton2;
  75.  
  76.   transform_core = (TransformCore *) tool->private;
  77.   gdisp = (GDisplay *) gdisp_ptr;
  78.  
  79.   switch (state)
  80.     {
  81.     case INIT:
  82.       angle_val = 0.0;
  83.       center_vals[0] = transform_core->cx;
  84.       center_vals[1] = transform_core->cy;
  85.  
  86.       if (!transform_info)
  87.     {
  88.       transform_info = info_dialog_new (_("Rotation Information"),
  89.                         gimp_standard_help_func,
  90.                         "tools/transform_rotate.html");
  91.  
  92.       widget =
  93.         info_dialog_add_spinbutton (transform_info, _("Angle:"),
  94.                     &angle_val,
  95.                     -180, 180, 1, 15, 1, 1, 2,
  96.                     (GtkSignalFunc) rotate_angle_changed,
  97.                     tool);
  98.       gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (widget), TRUE);
  99.  
  100.       /*  this looks strange (-180, 181), but it works  */
  101.       widget = info_dialog_add_scale (transform_info, "", &angle_val,
  102.                       -180, 181, 0.01, 0.1, 1, -1,
  103.                       (GtkSignalFunc) rotate_angle_changed,
  104.                       tool);
  105.       gtk_widget_set_usize (widget, 180, 0);
  106.  
  107.       spinbutton2 =
  108.         info_dialog_add_spinbutton (transform_info, _("Center X:"), NULL,
  109.                     -1, 1, 1, 10, 1, 1, 2, NULL, NULL);
  110.       sizeentry =
  111.         info_dialog_add_sizeentry (transform_info, _("Y:"),
  112.                        center_vals, 1,
  113.                        gdisp->gimage->unit, "%a",
  114.                        TRUE, TRUE, FALSE,
  115.                        GIMP_SIZE_ENTRY_UPDATE_SIZE,
  116.                        rotate_center_changed, tool);
  117.  
  118.       gimp_size_entry_add_field (GIMP_SIZE_ENTRY (sizeentry),
  119.                      GTK_SPIN_BUTTON (spinbutton2), NULL);
  120.  
  121.       gtk_table_set_row_spacing (GTK_TABLE (transform_info->info_table),
  122.                      1, 6);
  123.       gtk_table_set_row_spacing (GTK_TABLE (transform_info->info_table),
  124.                      2, 0);
  125.     }
  126.  
  127.       gtk_signal_handler_block_by_data (GTK_OBJECT (sizeentry), tool);
  128.  
  129.       gimp_size_entry_set_unit (GIMP_SIZE_ENTRY (sizeentry),
  130.                 gdisp->gimage->unit);
  131.       if (gdisp->dot_for_dot)
  132.     gimp_size_entry_set_unit (GIMP_SIZE_ENTRY (sizeentry), GIMP_UNIT_PIXEL);
  133.  
  134.       gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (sizeentry), 0,
  135.                       gdisp->gimage->xresolution, FALSE);
  136.       gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (sizeentry), 1,
  137.                       gdisp->gimage->yresolution, FALSE);
  138.  
  139.       gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), 0,
  140.                          -65536,
  141.                          65536 + gdisp->gimage->width);
  142.       gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), 1,
  143.                          -65536,
  144.                          65536 + gdisp->gimage->height);
  145.  
  146.       gimp_size_entry_set_size (GIMP_SIZE_ENTRY (sizeentry), 0,
  147.                 transform_core->x1, transform_core->x2);
  148.       gimp_size_entry_set_size (GIMP_SIZE_ENTRY (sizeentry), 1,
  149.                 transform_core->y1, transform_core->y2);
  150.  
  151.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (sizeentry), 0,
  152.                   center_vals[0]);
  153.       gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (sizeentry), 1,
  154.                   center_vals[1]);
  155.  
  156.       gtk_widget_set_sensitive (transform_info->shell, TRUE);
  157.  
  158.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (sizeentry), tool);
  159.  
  160.       transform_core->trans_info[ANGLE] = angle_val;
  161.       transform_core->trans_info[REAL_ANGLE] = angle_val;
  162.       transform_core->trans_info[CENTER_X] = center_vals[0];
  163.       transform_core->trans_info[CENTER_Y] = center_vals[1];
  164.  
  165.       return NULL;
  166.       break;
  167.  
  168.     case MOTION:
  169.       rotate_tool_motion (tool, gdisp_ptr);
  170.       rotate_tool_recalc (tool, gdisp_ptr);
  171.       break;
  172.  
  173.     case RECALC:
  174.       rotate_tool_recalc (tool, gdisp_ptr);
  175.       break;
  176.  
  177.     case FINISH:
  178.       gtk_widget_set_sensitive (GTK_WIDGET (transform_info->shell), FALSE);
  179.       return rotate_tool_rotate (gdisp->gimage,
  180.                  gimage_active_drawable (gdisp->gimage),
  181.                  gdisp,
  182.                  transform_core->trans_info[ANGLE],
  183.                  transform_core->original,
  184.                  transform_tool_smoothing (),
  185.                  transform_core->transform);
  186.       break;
  187.     }
  188.  
  189.   return NULL;
  190. }
  191.  
  192. Tool *
  193. tools_new_rotate_tool (void)
  194. {
  195.   Tool          *tool;
  196.   TransformCore *private;
  197.  
  198.   tool = transform_core_new (ROTATE, TRUE);
  199.  
  200.   private = tool->private;
  201.  
  202.   /*  set the rotation specific transformation attributes  */
  203.   private->trans_func = rotate_tool_transform;
  204.   private->trans_info[ANGLE]      = 0.0;
  205.   private->trans_info[REAL_ANGLE] = 0.0;
  206.   private->trans_info[CENTER_X]   = 0.0;
  207.   private->trans_info[CENTER_Y]   = 0.0;
  208.  
  209.   /*  assemble the transformation matrix  */
  210.   gimp_matrix3_identity (private->transform);
  211.  
  212.   return tool;
  213. }
  214.  
  215. void
  216. tools_free_rotate_tool (Tool *tool)
  217. {
  218.   transform_core_free (tool);
  219. }
  220.  
  221. static void
  222. rotate_info_update (Tool *tool)
  223. {
  224.   TransformCore *transform_core;
  225.  
  226.   transform_core = (TransformCore *) tool->private;
  227.  
  228.   angle_val      = gimp_rad_to_deg (transform_core->trans_info[ANGLE]);
  229.   center_vals[0] = transform_core->cx;
  230.   center_vals[1] = transform_core->cy;
  231.  
  232.   info_dialog_update (transform_info);
  233.   info_dialog_popup (transform_info);
  234. }
  235.  
  236. static void
  237. rotate_angle_changed (GtkWidget *widget,
  238.               gpointer   data)
  239. {
  240.   Tool          *tool;
  241.   GDisplay      *gdisp;
  242.   TransformCore *transform_core;
  243.   gdouble        value;
  244.  
  245.   tool = (Tool *) data;
  246.  
  247.   if (tool)
  248.     {
  249.       gdisp = (GDisplay *) tool->gdisp_ptr;
  250.       transform_core = (TransformCore *) tool->private;
  251.  
  252.       value = gimp_deg_to_rad (GTK_ADJUSTMENT (widget)->value);
  253.  
  254.       if (value != transform_core->trans_info[ANGLE])
  255.     {
  256.       draw_core_pause (transform_core->core, tool);      
  257.       transform_core->trans_info[ANGLE] = value;
  258.       rotate_tool_recalc (tool, gdisp);
  259.       draw_core_resume (transform_core->core, tool);
  260.     }
  261.     }
  262. }
  263.  
  264. static void
  265. rotate_center_changed (GtkWidget *widget,
  266.                gpointer   data)
  267. {
  268.   Tool          *tool;
  269.   GDisplay      *gdisp;
  270.   TransformCore *transform_core;
  271.   gint           cx;
  272.   gint           cy;
  273.  
  274.   tool = (Tool *) data;
  275.  
  276.   if (tool)
  277.     {
  278.       gdisp = (GDisplay *) tool->gdisp_ptr;
  279.       transform_core = (TransformCore *) tool->private;
  280.  
  281.       cx = RINT (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (widget), 0));
  282.       cy = RINT (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (widget), 1));
  283.  
  284.       if ((cx != transform_core->cx) ||
  285.       (cy != transform_core->cy))
  286.     {
  287.       draw_core_pause (transform_core->core, tool);      
  288.       transform_core->cx = cx;
  289.       transform_core->cy = cy;
  290.       rotate_tool_recalc (tool, gdisp);
  291.       draw_core_resume (transform_core->core, tool);
  292.     }
  293.     }
  294. }
  295.  
  296. static void
  297. rotate_tool_motion (Tool *tool,
  298.             void *gdisp_ptr)
  299. {
  300.   TransformCore *transform_core;
  301.   gdouble        angle1, angle2, angle;
  302.   gdouble        cx, cy;
  303.   gdouble        x1, y1, x2, y2;
  304.  
  305.   transform_core = (TransformCore *) tool->private;
  306.  
  307.   if (transform_core->function == HANDLE_CENTER)
  308.     {
  309.       transform_core->cx = transform_core->curx;
  310.       transform_core->cy = transform_core->cury;
  311.  
  312.       return;
  313.     }
  314.  
  315.   cx = transform_core->cx;
  316.   cy = transform_core->cy;
  317.  
  318.   x1 = transform_core->curx - cx;
  319.   x2 = transform_core->lastx - cx;
  320.   y1 = cy - transform_core->cury;
  321.   y2 = cy - transform_core->lasty;
  322.  
  323.   /*  find the first angle  */
  324.   angle1 = atan2 (y1, x1);
  325.  
  326.   /*  find the angle  */
  327.   angle2 = atan2 (y2, x2);
  328.  
  329.   angle = angle2 - angle1;
  330.  
  331.   if (angle > G_PI || angle < -G_PI)
  332.     angle = angle2 - ((angle1 < 0) ? 2.0 * G_PI + angle1 : angle1 - 2.0 * G_PI);
  333.  
  334.   /*  increment the transform tool's angle  */
  335.   transform_core->trans_info[REAL_ANGLE] += angle;
  336.  
  337.   /*  limit the angle to between 0 and 360 degrees  */
  338.   if (transform_core->trans_info[REAL_ANGLE] < - G_PI)
  339.     transform_core->trans_info[REAL_ANGLE] =
  340.       2.0 * G_PI - transform_core->trans_info[REAL_ANGLE];
  341.   else if (transform_core->trans_info[REAL_ANGLE] > G_PI)
  342.     transform_core->trans_info[REAL_ANGLE] =
  343.       transform_core->trans_info[REAL_ANGLE] - 2.0 * G_PI;
  344.  
  345.   /*  constrain the angle to 15-degree multiples if ctrl is held down  */
  346.   if (transform_core->state & GDK_CONTROL_MASK)
  347.     transform_core->trans_info[ANGLE] =
  348.       FIFTEEN_DEG * (int) ((transform_core->trans_info[REAL_ANGLE] +
  349.                 FIFTEEN_DEG / 2.0) /
  350.                FIFTEEN_DEG);
  351.   else
  352.     transform_core->trans_info[ANGLE] = transform_core->trans_info[REAL_ANGLE];
  353. }
  354.  
  355. static void
  356. rotate_tool_recalc (Tool *tool,
  357.             void *gdisp_ptr)
  358. {
  359.   TransformCore *transform_core;
  360.   GDisplay      *gdisp;
  361.   gdouble        cx, cy;
  362.  
  363.   gdisp = (GDisplay *) tool->gdisp_ptr;
  364.   transform_core = (TransformCore *) tool->private;
  365.  
  366.   cx = transform_core->cx;
  367.   cy = transform_core->cy;
  368.  
  369.   /*  assemble the transformation matrix  */
  370.   gimp_matrix3_identity  (transform_core->transform);
  371.   gimp_matrix3_translate (transform_core->transform, -cx, -cy);
  372.   gimp_matrix3_rotate    (transform_core->transform,
  373.               transform_core->trans_info[ANGLE]);
  374.   gimp_matrix3_translate (transform_core->transform, +cx, +cy);
  375.  
  376.   /*  transform the bounding box  */
  377.   transform_core_transform_bounding_box (tool);
  378.  
  379.   /*  update the information dialog  */
  380.   rotate_info_update (tool);
  381. }
  382.  
  383. TileManager *
  384. rotate_tool_rotate (GImage       *gimage,
  385.             GimpDrawable *drawable,
  386.             GDisplay     *gdisp,
  387.             gdouble       angle,
  388.             TileManager  *float_tiles,
  389.             gboolean      interpolation,
  390.             GimpMatrix3   matrix)
  391. {
  392.   gimp_progress *progress;
  393.   TileManager   *ret;
  394.  
  395.   progress = progress_start (gdisp, _("Rotating..."), FALSE, NULL, NULL);
  396.  
  397.   ret = transform_core_do (gimage, drawable, float_tiles,
  398.                interpolation, matrix,
  399.                progress ? progress_update_and_flush :
  400.                (progress_func_t) NULL,
  401.                progress);
  402.  
  403.   if (progress)
  404.     progress_end (progress);
  405.  
  406.   return ret;
  407. }
  408.