Applied the transform tool UI patch from Tor Lillqvist <tml@iki.fi>.

It still has a few problems, but I guess there are easier to solve, if the
patch is applied.


--Sven
This commit is contained in:
Sven Neumann 1998-08-13 20:19:09 +00:00
parent fb8a4ebeed
commit 844a3481ee
17 changed files with 840 additions and 353 deletions

View File

@ -1,3 +1,43 @@
Thu Aug 13 22:16:42 MEST 1998 Sven Neumann <sven@gimp.org>
Applied the patch from Tor Lillqvist <tml@iki.fi>:
* app/transform_core.c app/transform_core.h: Further changes in
the look-and-feel. Now we have a info_dialog window for each
transformation tool, with an action and cancel button. The use of
shift-clicking to approve the transform introduced in
gimp-tml-980724-1 is still there. The old immediate transformation
on button release is gone.
For use by the rotate tool we have a center-of-rotation point
which is draggable. Its coordinates are kept in the TransformCore
struct.
As there no longer are several related transformations done after
each other as in the old look-and-feel, we don't need the _first_
field in TransformUndo.
Added the function _transform_core_grid_density_changed_ called
from transform_tool.c when the grid density spinbutton has been
changed. The grid is instantaneously redrawn in the new
density. Neat, huh?
* transform_tool.c transform_tool.h: More options: a toggle to
clip the result of a perspective transform, and a spinbutton for
the rubber-band grid density. The toggle for "new" vs. "old" UI is
now for "corrective" vs. "traditional" paradigm.
* rotate_tool.c: Show also the center point coordinates in the
info dialog. If dragging the center point, update TransformCore
accordingly. Use the center point coordinates from TransformCore
where appropriate.
* perspective_tool.c: Show the transformation matrix in the info
dialog.
* undo.c: TransformUndo no longed has the _first_ field, code
simplified thusly.
Thu Aug 13 20:48:48 MEST 1998 Sven Neumann <sven@gimp.org>
* app/color_area.c: Add event-masks so the tooltip is shown.

View File

@ -937,21 +937,17 @@ undo_pop_transform (GImage *gimage,
tc->trans_info[i] = d;
}
/* if this is the first transform in a string, swap the
* original buffer--the source buffer for repeated transforms
/* swap the original buffer--the source buffer for repeated transforms
*/
if (tu->first)
{
temp = tu->original;
tu->original = tc->original;
tc->original = temp;
temp = tu->original;
tu->original = tc->original;
tc->original = temp;
/* If we're re-implementing the first transform, reactivate tool */
if (state == REDO && tc->original)
{
active_tool->state = ACTIVE;
draw_core_resume (tc->core, active_tool);
}
/* If we're re-implementing the first transform, reactivate tool */
if (state == REDO && tc->original)
{
active_tool->state = ACTIVE;
draw_core_resume (tc->core, active_tool);
}
return TRUE;

View File

@ -16,6 +16,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include "appenv.h"
#include "drawable.h"
#include "gdisplay.h"
@ -40,9 +41,7 @@
#define Y3 7
/* storage for information dialog fields */
char matrix_row1_buf [256];
char matrix_row2_buf [256];
char matrix_row3_buf [256];
static char matrix_row_buf [3][MAX_INFO_BUF];
/* forward function declarations */
static void * perspective_tool_perspective (GImage *, GimpDrawable *, TileManager *, int, Matrix);
@ -67,7 +66,16 @@ perspective_tool_transform (tool, gdisp_ptr, state)
switch (state)
{
case INIT :
transform_info = NULL;
if (!transform_info)
{
transform_info = info_dialog_new ("Perspective Transform Information");
info_dialog_add_field (transform_info, "Matrix: ",
matrix_row_buf[0]);
info_dialog_add_field (transform_info, " ",
matrix_row_buf[1]);
info_dialog_add_field (transform_info, " ",
matrix_row_buf[2]);
}
transform_core->trans_info [X0] = (double) transform_core->x1;
transform_core->trans_info [Y0] = (double) transform_core->y1;
@ -143,6 +151,25 @@ static void
perspective_info_update (tool)
Tool * tool;
{
TransformCore * transform_core;
int i;
transform_core = (TransformCore *) tool->private;
for (i = 0; i < 3; i++)
{
char *p = matrix_row_buf[i];
int j;
for (j = 0; j < 3; j++)
{
p += sprintf (p, "%10.3g", transform_core->transform[i][j]);
}
}
info_dialog_update (transform_info);
info_dialog_popup (transform_info);
return;
}

View File

@ -40,11 +40,16 @@
/* index into trans_info array */
#define ANGLE 0
#define REAL_ANGLE 1
#define CENTER_X 2
#define CENTER_Y 3
#define EPSILON 0.018 /* ~ 1 degree */
#define FIFTEEN_DEG (M_PI / 12.0)
/* variables local to this file */
char angle_buf [MAX_INFO_BUF];
static char angle_buf [MAX_INFO_BUF];
static char center_x_buf [MAX_INFO_BUF];
static char center_y_buf [MAX_INFO_BUF];
/* forward function declarations */
static void * rotate_tool_rotate (GImage *, GimpDrawable *, double, TileManager *, int, Matrix);
@ -72,10 +77,16 @@ rotate_tool_transform (tool, gdisp_ptr, state)
{
transform_info = info_dialog_new ("Rotation Information");
info_dialog_add_field (transform_info, "Angle: ", angle_buf);
info_dialog_add_field (transform_info, "Center X: ", center_x_buf);
info_dialog_add_field (transform_info, "Center Y: ", center_y_buf);
}
transform_core->trans_info[ANGLE] = 0.0;
transform_core->trans_info[REAL_ANGLE] = 0.0;
transform_core->trans_info[CENTER_X] =
(transform_core->x1 + transform_core->x2) / 2;
transform_core->trans_info[CENTER_Y] =
(transform_core->y1 + transform_core->y2) / 2;
return NULL;
break;
@ -114,6 +125,8 @@ tools_new_rotate_tool ()
private->trans_func = rotate_tool_transform;
private->trans_info[ANGLE] = 0.0;
private->trans_info[REAL_ANGLE] = 0.0;
private->trans_info[CENTER_X] = (private->x1 + private->x2) / 2;
private->trans_info[CENTER_Y] = (private->y1 + private->y2) / 2;
/* assemble the transformation matrix */
identity_matrix (private->transform);
@ -135,13 +148,18 @@ rotate_info_update (tool)
GDisplay * gdisp;
TransformCore * transform_core;
double angle;
int cx, cy;
gdisp = (GDisplay *) tool->gdisp_ptr;
transform_core = (TransformCore *) tool->private;
angle = (transform_core->trans_info[ANGLE] * 180.0) / M_PI;
cx = transform_core->cx;
cy = transform_core->cy;
sprintf (angle_buf, "%0.2f", angle);
sprintf (center_x_buf, "%d", cx);
sprintf (center_y_buf, "%d", cy);
info_dialog_update (transform_info);
info_dialog_popup (transform_info);
@ -159,8 +177,16 @@ rotate_tool_motion (tool, gdisp_ptr)
transform_core = (TransformCore *) tool->private;
cx = (transform_core->x1 + transform_core->x2) / 2.0;
cy = (transform_core->y1 + transform_core->y2) / 2.0;
if (transform_core->function == HANDLE_CENTER)
{
transform_core->cx = transform_core->curx;
transform_core->cy = transform_core->cury;
return;
}
cx = transform_core->cx;
cy = transform_core->cy;
x1 = transform_core->curx - cx;
x2 = transform_core->lastx - cx;
@ -209,8 +235,8 @@ rotate_tool_recalc (tool, gdisp_ptr)
gdisp = (GDisplay *) tool->gdisp_ptr;
transform_core = (TransformCore *) tool->private;
cx = (transform_core->x1 + transform_core->x2) / 2.0;
cy = (transform_core->y1 + transform_core->y2) / 2.0;
cx = transform_core->cx;
cy = transform_core->cy;
/* assemble the transformation matrix */
identity_matrix (transform_core->transform);

View File

@ -16,6 +16,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include "appenv.h"
#include "drawable.h"
#include "gdisplay.h"
@ -40,9 +41,7 @@
#define Y3 7
/* storage for information dialog fields */
char matrix_row1_buf [256];
char matrix_row2_buf [256];
char matrix_row3_buf [256];
static char matrix_row_buf [3][MAX_INFO_BUF];
/* forward function declarations */
static void * perspective_tool_perspective (GImage *, GimpDrawable *, TileManager *, int, Matrix);
@ -67,7 +66,16 @@ perspective_tool_transform (tool, gdisp_ptr, state)
switch (state)
{
case INIT :
transform_info = NULL;
if (!transform_info)
{
transform_info = info_dialog_new ("Perspective Transform Information");
info_dialog_add_field (transform_info, "Matrix: ",
matrix_row_buf[0]);
info_dialog_add_field (transform_info, " ",
matrix_row_buf[1]);
info_dialog_add_field (transform_info, " ",
matrix_row_buf[2]);
}
transform_core->trans_info [X0] = (double) transform_core->x1;
transform_core->trans_info [Y0] = (double) transform_core->y1;
@ -143,6 +151,25 @@ static void
perspective_info_update (tool)
Tool * tool;
{
TransformCore * transform_core;
int i;
transform_core = (TransformCore *) tool->private;
for (i = 0; i < 3; i++)
{
char *p = matrix_row_buf[i];
int j;
for (j = 0; j < 3; j++)
{
p += sprintf (p, "%10.3g", transform_core->transform[i][j]);
}
}
info_dialog_update (transform_info);
info_dialog_popup (transform_info);
return;
}

View File

@ -40,11 +40,16 @@
/* index into trans_info array */
#define ANGLE 0
#define REAL_ANGLE 1
#define CENTER_X 2
#define CENTER_Y 3
#define EPSILON 0.018 /* ~ 1 degree */
#define FIFTEEN_DEG (M_PI / 12.0)
/* variables local to this file */
char angle_buf [MAX_INFO_BUF];
static char angle_buf [MAX_INFO_BUF];
static char center_x_buf [MAX_INFO_BUF];
static char center_y_buf [MAX_INFO_BUF];
/* forward function declarations */
static void * rotate_tool_rotate (GImage *, GimpDrawable *, double, TileManager *, int, Matrix);
@ -72,10 +77,16 @@ rotate_tool_transform (tool, gdisp_ptr, state)
{
transform_info = info_dialog_new ("Rotation Information");
info_dialog_add_field (transform_info, "Angle: ", angle_buf);
info_dialog_add_field (transform_info, "Center X: ", center_x_buf);
info_dialog_add_field (transform_info, "Center Y: ", center_y_buf);
}
transform_core->trans_info[ANGLE] = 0.0;
transform_core->trans_info[REAL_ANGLE] = 0.0;
transform_core->trans_info[CENTER_X] =
(transform_core->x1 + transform_core->x2) / 2;
transform_core->trans_info[CENTER_Y] =
(transform_core->y1 + transform_core->y2) / 2;
return NULL;
break;
@ -114,6 +125,8 @@ tools_new_rotate_tool ()
private->trans_func = rotate_tool_transform;
private->trans_info[ANGLE] = 0.0;
private->trans_info[REAL_ANGLE] = 0.0;
private->trans_info[CENTER_X] = (private->x1 + private->x2) / 2;
private->trans_info[CENTER_Y] = (private->y1 + private->y2) / 2;
/* assemble the transformation matrix */
identity_matrix (private->transform);
@ -135,13 +148,18 @@ rotate_info_update (tool)
GDisplay * gdisp;
TransformCore * transform_core;
double angle;
int cx, cy;
gdisp = (GDisplay *) tool->gdisp_ptr;
transform_core = (TransformCore *) tool->private;
angle = (transform_core->trans_info[ANGLE] * 180.0) / M_PI;
cx = transform_core->cx;
cy = transform_core->cy;
sprintf (angle_buf, "%0.2f", angle);
sprintf (center_x_buf, "%d", cx);
sprintf (center_y_buf, "%d", cy);
info_dialog_update (transform_info);
info_dialog_popup (transform_info);
@ -159,8 +177,16 @@ rotate_tool_motion (tool, gdisp_ptr)
transform_core = (TransformCore *) tool->private;
cx = (transform_core->x1 + transform_core->x2) / 2.0;
cy = (transform_core->y1 + transform_core->y2) / 2.0;
if (transform_core->function == HANDLE_CENTER)
{
transform_core->cx = transform_core->curx;
transform_core->cy = transform_core->cury;
return;
}
cx = transform_core->cx;
cy = transform_core->cy;
x1 = transform_core->curx - cx;
x2 = transform_core->lastx - cx;
@ -209,8 +235,8 @@ rotate_tool_recalc (tool, gdisp_ptr)
gdisp = (GDisplay *) tool->gdisp_ptr;
transform_core = (TransformCore *) tool->private;
cx = (transform_core->x1 + transform_core->x2) / 2.0;
cy = (transform_core->y1 + transform_core->y2) / 2.0;
cx = transform_core->cx;
cy = transform_core->cy;
/* assemble the transformation matrix */
identity_matrix (transform_core->transform);

View File

@ -16,6 +16,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include "appenv.h"
#include "drawable.h"
#include "gdisplay.h"
@ -40,9 +41,7 @@
#define Y3 7
/* storage for information dialog fields */
char matrix_row1_buf [256];
char matrix_row2_buf [256];
char matrix_row3_buf [256];
static char matrix_row_buf [3][MAX_INFO_BUF];
/* forward function declarations */
static void * perspective_tool_perspective (GImage *, GimpDrawable *, TileManager *, int, Matrix);
@ -67,7 +66,16 @@ perspective_tool_transform (tool, gdisp_ptr, state)
switch (state)
{
case INIT :
transform_info = NULL;
if (!transform_info)
{
transform_info = info_dialog_new ("Perspective Transform Information");
info_dialog_add_field (transform_info, "Matrix: ",
matrix_row_buf[0]);
info_dialog_add_field (transform_info, " ",
matrix_row_buf[1]);
info_dialog_add_field (transform_info, " ",
matrix_row_buf[2]);
}
transform_core->trans_info [X0] = (double) transform_core->x1;
transform_core->trans_info [Y0] = (double) transform_core->y1;
@ -143,6 +151,25 @@ static void
perspective_info_update (tool)
Tool * tool;
{
TransformCore * transform_core;
int i;
transform_core = (TransformCore *) tool->private;
for (i = 0; i < 3; i++)
{
char *p = matrix_row_buf[i];
int j;
for (j = 0; j < 3; j++)
{
p += sprintf (p, "%10.3g", transform_core->transform[i][j]);
}
}
info_dialog_update (transform_info);
info_dialog_popup (transform_info);
return;
}

View File

@ -40,11 +40,16 @@
/* index into trans_info array */
#define ANGLE 0
#define REAL_ANGLE 1
#define CENTER_X 2
#define CENTER_Y 3
#define EPSILON 0.018 /* ~ 1 degree */
#define FIFTEEN_DEG (M_PI / 12.0)
/* variables local to this file */
char angle_buf [MAX_INFO_BUF];
static char angle_buf [MAX_INFO_BUF];
static char center_x_buf [MAX_INFO_BUF];
static char center_y_buf [MAX_INFO_BUF];
/* forward function declarations */
static void * rotate_tool_rotate (GImage *, GimpDrawable *, double, TileManager *, int, Matrix);
@ -72,10 +77,16 @@ rotate_tool_transform (tool, gdisp_ptr, state)
{
transform_info = info_dialog_new ("Rotation Information");
info_dialog_add_field (transform_info, "Angle: ", angle_buf);
info_dialog_add_field (transform_info, "Center X: ", center_x_buf);
info_dialog_add_field (transform_info, "Center Y: ", center_y_buf);
}
transform_core->trans_info[ANGLE] = 0.0;
transform_core->trans_info[REAL_ANGLE] = 0.0;
transform_core->trans_info[CENTER_X] =
(transform_core->x1 + transform_core->x2) / 2;
transform_core->trans_info[CENTER_Y] =
(transform_core->y1 + transform_core->y2) / 2;
return NULL;
break;
@ -114,6 +125,8 @@ tools_new_rotate_tool ()
private->trans_func = rotate_tool_transform;
private->trans_info[ANGLE] = 0.0;
private->trans_info[REAL_ANGLE] = 0.0;
private->trans_info[CENTER_X] = (private->x1 + private->x2) / 2;
private->trans_info[CENTER_Y] = (private->y1 + private->y2) / 2;
/* assemble the transformation matrix */
identity_matrix (private->transform);
@ -135,13 +148,18 @@ rotate_info_update (tool)
GDisplay * gdisp;
TransformCore * transform_core;
double angle;
int cx, cy;
gdisp = (GDisplay *) tool->gdisp_ptr;
transform_core = (TransformCore *) tool->private;
angle = (transform_core->trans_info[ANGLE] * 180.0) / M_PI;
cx = transform_core->cx;
cy = transform_core->cy;
sprintf (angle_buf, "%0.2f", angle);
sprintf (center_x_buf, "%d", cx);
sprintf (center_y_buf, "%d", cy);
info_dialog_update (transform_info);
info_dialog_popup (transform_info);
@ -159,8 +177,16 @@ rotate_tool_motion (tool, gdisp_ptr)
transform_core = (TransformCore *) tool->private;
cx = (transform_core->x1 + transform_core->x2) / 2.0;
cy = (transform_core->y1 + transform_core->y2) / 2.0;
if (transform_core->function == HANDLE_CENTER)
{
transform_core->cx = transform_core->curx;
transform_core->cy = transform_core->cury;
return;
}
cx = transform_core->cx;
cy = transform_core->cy;
x1 = transform_core->curx - cx;
x2 = transform_core->lastx - cx;
@ -209,8 +235,8 @@ rotate_tool_recalc (tool, gdisp_ptr)
gdisp = (GDisplay *) tool->gdisp_ptr;
transform_core = (TransformCore *) tool->private;
cx = (transform_core->x1 + transform_core->x2) / 2.0;
cy = (transform_core->y1 + transform_core->y2) / 2.0;
cx = transform_core->cx;
cy = transform_core->cy;
/* assemble the transformation matrix */
identity_matrix (transform_core->transform);

View File

@ -18,6 +18,7 @@
#include <stdlib.h>
#include <math.h>
#include "appenv.h"
#include "actionarea.h"
#include "drawable.h"
#include "errors.h"
#include "floating_sel.h"
@ -48,7 +49,6 @@
/* variables */
static TranInfo old_trans_info;
static int new_ui;
InfoDialog * transform_info = NULL;
/* forward function declarations */
@ -68,6 +68,52 @@ static void invert (Matrix, Matrix);
src[i] = tile_data_pointer (tile[i], (x) % TILE_WIDTH, (y) % TILE_HEIGHT);
static void
transform_ok_callback (GtkWidget *w,
gpointer client_data)
{
Tool *tool;
tool = (Tool *) client_data;
transform_core_doit (tool, tool->gdisp_ptr);
}
static void
transform_cancel_callback (GtkWidget *w,
gpointer client_data)
{
Tool *tool;
TransformCore *transform_core;
int i;
tool = (Tool *) client_data;
transform_core = (TransformCore *) tool->private;
/* stop the current tool drawing process */
draw_core_pause (transform_core->core, tool);
/* Restore the previous transformation info */
for (i = 0; i < TRAN_INFO_SIZE; i++)
transform_core->trans_info [i] = old_trans_info [i];
/* recalculate the tool's transformation matrix */
transform_core_recalc (tool, tool->gdisp_ptr);
/* resume drawing the current tool */
draw_core_resume (transform_core->core, tool);
}
static ActionAreaItem action_items[2] =
{
{ NULL, transform_ok_callback, NULL, NULL },
{ "Cancel", transform_cancel_callback, NULL, NULL },
};
static char *action_labels[4] =
{
"Rotate", "Scale", "Shear", "Transform"
};
void
transform_core_button_press (tool, bevent, gdisp_ptr)
Tool *tool;
@ -90,7 +136,7 @@ transform_core_button_press (tool, bevent, gdisp_ptr)
tool->drawable = gimage_active_drawable (gdisp->gimage);
if (transform_core->function == CREATING)
if (transform_core->function == CREATING && tool->state == ACTIVE)
{
/* Save the current transformation info */
for (i = 0; i < TRAN_INFO_SIZE; i++)
@ -105,6 +151,9 @@ transform_core_button_press (tool, bevent, gdisp_ptr)
if ((transform_core->function >= CREATING) && (gdisp_ptr == tool->gdisp_ptr) &&
transform_core->interactive)
{
/* start drawing the bounding box and handles... */
draw_core_start (transform_core->core, gdisp->canvas->window, tool);
x = bevent->x;
y = bevent->y;
@ -132,6 +181,13 @@ transform_core_button_press (tool, bevent, gdisp_ptr)
transform_core->function = HANDLE_4;
}
if (tool->type == ROTATE
&& (SQR (x - transform_core->scx) +
SQR (y - transform_core->scy)) <= 100)
{
transform_core->function = HANDLE_CENTER;
}
/* Save the current pointer position */
gdisplay_untransform_coords (gdisp, bevent->x, bevent->y,
&transform_core->startx,
@ -143,10 +199,6 @@ transform_core_button_press (tool, bevent, gdisp_ptr)
GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
NULL, NULL, bevent->time);
/* start drawing the bounding box and handles... */
if (new_ui)
draw_core_start (transform_core->core, gdisp->canvas->window, tool);
tool->state = ACTIVE;
return;
}
@ -192,20 +244,24 @@ transform_core_button_press (tool, bevent, gdisp_ptr)
*/
transform_core_bounds (tool, gdisp_ptr);
/* If new UI, calculate the grid line endpoints */
if (new_ui)
transform_core_setup_grid (tool);
/* Calculate the grid line endpoints */
transform_core_setup_grid (tool);
/* Initialize the transform tool */
(* transform_core->trans_func) (tool, gdisp_ptr, INIT);
if (transform_info != NULL)
{
action_items[0].label = action_labels[tool->type - ROTATE];
action_items[0].user_data = tool;
action_items[1].user_data = tool;
build_action_area (GTK_DIALOG (transform_info->shell),
action_items, 2, 0);
}
/* Recalculate the transform tool */
transform_core_recalc (tool, gdisp_ptr);
/* start drawing the bounding box and handles... */
if (!new_ui)
draw_core_start (transform_core->core, gdisp->canvas->window, tool);
/* recall this function to find which handle we're dragging */
if (transform_core->interactive)
transform_core_button_press (tool, bevent, gdisp_ptr);
@ -239,23 +295,16 @@ transform_core_button_release (tool, bevent, gdisp_ptr)
/* if the 3rd button isn't pressed, transform the selected mask */
if (! (bevent->state & GDK_BUTTON3_MASK))
{
if (new_ui)
/* Shift-clicking is another way to approve the transform */
if ((bevent->state & GDK_SHIFT_MASK)
|| (tool->type == FLIP_HORZ)
|| (tool->type == FLIP_VERT))
{
/* In the new UI, shift-clicking means perform the transform */
if ((bevent->state & GDK_SHIFT_MASK)
|| (tool->type == FLIP_HORZ)
|| (tool->type == FLIP_VERT))
{
transform_core_doit (tool, gdisp_ptr);
}
else
{
/* Do nothing, keep the grid visible */
}
transform_core_doit (tool, gdisp_ptr);
}
else
{
transform_core_doit (tool, gdisp_ptr);
/* Do nothing, keep the grid visible */
}
}
else
@ -266,7 +315,6 @@ transform_core_button_release (tool, bevent, gdisp_ptr)
/* Restore the previous transformation info */
for (i = 0; i < TRAN_INFO_SIZE; i++)
transform_core->trans_info [i] = old_trans_info [i];
/* recalculate the tool's transformation matrix */
transform_core_recalc (tool, gdisp_ptr);
@ -288,7 +336,6 @@ transform_core_doit (tool, gdisp_ptr)
TransformCore *transform_core;
TileManager *new_tiles;
TransformUndo *tu;
int first_transform;
int new_layer;
int i, x, y;
@ -304,35 +351,25 @@ transform_core_doit (tool, gdisp_ptr)
/* Start a transform undo group */
undo_push_group_start (gdisp->gimage, TRANSFORM_CORE_UNDO);
/* If original is NULL, then this is the first transformation */
first_transform = (transform_core->original) ? FALSE : TRUE;
/* With the old UI, if original is NULL, then this is the
first transformation. In the new UI, it is always so, yes? */
g_assert (transform_core->original == NULL);
/* If we're in interactive mode, and haven't yet done any
* transformations, we need to copy the current selection to
* the transform tool's private selection pointer, so that the
* original source can be repeatedly modified.
/* If we're in interactive mode, we need to copy the current
* selection to the transform tool's private selection pointer, so
* that the original source can be repeatedly modified.
*/
if (first_transform)
transform_core->original = transform_core_cut (gdisp->gimage,
gimage_active_drawable (gdisp->gimage),
&new_layer);
else
new_layer = FALSE;
transform_core->original = transform_core_cut (gdisp->gimage,
gimage_active_drawable (gdisp->gimage),
&new_layer);
/* Send the request for the transformation to the tool...
*/
new_tiles = (* transform_core->trans_func) (tool, gdisp_ptr, FINISH);
/* If new UI, reset the transformation */
if (new_ui)
{
int i;
for (i = 0; i < TRAN_INFO_SIZE; i++)
transform_core->trans_info [i] = 0;
transform_core_recalc (tool, gdisp_ptr);
}
(* transform_core->trans_func) (tool, gdisp_ptr, INIT);
transform_core_recalc (tool, gdisp_ptr);
if (new_tiles)
{
@ -348,7 +385,6 @@ transform_core_doit (tool, gdisp_ptr)
tu->tool_type = tool->type;
for (i = 0; i < TRAN_INFO_SIZE; i++)
tu->trans_info[i] = old_trans_info[i];
tu->first = first_transform;
tu->original = NULL;
/* Make a note of the new current drawable (since we may have
@ -389,10 +425,7 @@ transform_core_doit (tool, gdisp_ptr)
}
gdisplays_flush ();
if (new_ui)
{
transform_core_reset (tool, gdisp_ptr);
}
transform_core_reset (tool, gdisp_ptr);
/* if this tool is non-interactive, make it inactive after use */
if (!transform_core->interactive)
@ -534,6 +567,8 @@ transform_core_draw (tool)
TransformCore * transform_core;
GDisplay * gdisp;
int srw, srh;
int i, k, gci;
int xa, ya, xb, yb;
gdisp = tool->gdisp_ptr;
transform_core = (TransformCore *) tool->private;
@ -566,27 +601,22 @@ transform_core_draw (tool)
gdk_draw_line (transform_core->core->win, transform_core->core->gc,
x3, y3, x1, y1);
/* if new UI, draw the grid */
if (new_ui)
{
int i, k, gci;
int xa, ya, xb, yb;
/* Draw the grid */
gci = 0;
k = transform_core->ngx + transform_core->ngy;
for (i = 0; i < k; i++)
{
gdisplay_transform_coords (gdisp, transform_core->tgrid_coords[gci],
transform_core->tgrid_coords[gci+1],
&xa, &ya, 0);
gdisplay_transform_coords (gdisp, transform_core->tgrid_coords[gci+2],
transform_core->tgrid_coords[gci+3],
&xb, &yb, 0);
gdk_draw_line (transform_core->core->win, transform_core->core->gc,
xa, ya, xb, yb);
gci += 4;
}
gci = 0;
k = transform_core->ngx + transform_core->ngy;
for (i = 0; i < k; i++)
{
gdisplay_transform_coords (gdisp, transform_core->tgrid_coords[gci],
transform_core->tgrid_coords[gci+1],
&xa, &ya, 0);
gdisplay_transform_coords (gdisp, transform_core->tgrid_coords[gci+2],
transform_core->tgrid_coords[gci+3],
&xb, &yb, 0);
gdk_draw_line (transform_core->core->win, transform_core->core->gc,
xa, ya, xb, yb);
gci += 4;
}
/* draw the tool handles */
@ -598,6 +628,18 @@ transform_core_draw (tool)
x3 - (srw >> 1), y3 - (srh >> 1), srw, srh);
gdk_draw_rectangle (transform_core->core->win, transform_core->core->gc, 0,
x4 - (srw >> 1), y4 - (srh >> 1), srw, srh);
/* draw the center */
if (tool->type == ROTATE)
{
gdisplay_transform_coords (gdisp, transform_core->tcx, transform_core->tcy,
&transform_core->scx, &transform_core->scy, 0);
gdk_draw_arc (transform_core->core->win, transform_core->core->gc, 1,
transform_core->scx - (srw >> 1),
transform_core->scy - (srh >> 1),
srw, srh, 0, 23040);
}
}
Tool *
@ -629,15 +671,6 @@ transform_core_new (type, interactive)
private->grid_coords = private->tgrid_coords = NULL;
/* We must save this setting so that the user won't screw us if he
* changes the UI to "old" style in the middle of a "new" UI operation.
* We can't keep this info in the transform_core, as it is needed
* in transform_core_do, which doesn't have access to any TransformCore.
* I hope it's OK to use a static variable... (there already is
* old_trans_info, so?).
*/
new_ui = transform_tool_new_ui ();
tool->type = type;
tool->state = INACTIVE;
tool->scroll_lock = 1; /* Do not allow scrolling */
@ -693,6 +726,8 @@ transform_bounding_box (tool)
Tool * tool;
{
TransformCore * transform_core;
int i, k;
int gci;
transform_core = (TransformCore *) tool->private;
@ -709,22 +744,21 @@ transform_bounding_box (tool)
transform_core->x2, transform_core->y2,
&transform_core->tx4, &transform_core->ty4);
if (new_ui)
if (tool->type == ROTATE)
transform_point (transform_core->transform,
transform_core->cx, transform_core->cy,
&transform_core->tcx, &transform_core->tcy);
gci = 0;
k = (transform_core->ngx + transform_core->ngy) * 2;
for (i = 0; i < k; i++)
{
int i, k;
int gci;
gci = 0;
k = (transform_core->ngx + transform_core->ngy) * 2;
for (i = 0; i < k; i++)
{
transform_point (transform_core->transform,
transform_core->grid_coords[gci],
transform_core->grid_coords[gci+1],
&(transform_core->tgrid_coords[gci]),
&(transform_core->tgrid_coords[gci+1]));
gci += 2;
}
transform_point (transform_core->transform,
transform_core->grid_coords[gci],
transform_core->grid_coords[gci+1],
&(transform_core->tgrid_coords[gci]),
&(transform_core->tgrid_coords[gci+1]));
gci += 2;
}
}
@ -973,10 +1007,26 @@ transform_core_bounds (tool, gdisp_ptr)
transform_core->x2 += offset_x;
transform_core->y2 += offset_y;
}
transform_core->cx = (transform_core->x1 + transform_core->x2) / 2;
transform_core->cy = (transform_core->y1 + transform_core->y2) / 2;
return TRUE;
}
void
transform_core_grid_density_changed ()
{
TransformCore * transform_core;
transform_core = (TransformCore *) active_tool->private;
draw_core_pause (transform_core->core, active_tool);
g_free (transform_core->grid_coords);
g_free (transform_core->tgrid_coords);
transform_core_setup_grid (active_tool);
transform_bounding_box (active_tool);
draw_core_resume (transform_core->core, active_tool);
}
static void
transform_core_setup_grid (tool)
Tool *tool;
@ -988,7 +1038,7 @@ transform_core_setup_grid (tool)
transform_core = (TransformCore *) tool->private;
/* We use the transform_tool_grid_size function only here, even if the
* user changes the grid size in the middle of a "new" UI
* user changes the grid size in the middle of a
* operation, nothing happens.
*/
transform_core->ngx =
@ -1066,7 +1116,6 @@ transform_core_do (gimage, drawable, float_tiles, interpolation, matrix)
int plus2_x, plus2_y;
int minus_x, minus_y;
int x1, y1, x2, y2;
double dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4;
double xinc, yinc, winc;
double tx, ty, tw;
double ttx = 0.0, tty = 0.0;
@ -1104,7 +1153,7 @@ transform_core_do (gimage, drawable, float_tiles, interpolation, matrix)
break;
}
if (new_ui)
if (transform_tool_direction () == TRANSFORM_CORRECTIVE)
{
invert (matrix, im);
matrix = im;
@ -1118,24 +1167,36 @@ transform_core_do (gimage, drawable, float_tiles, interpolation, matrix)
x2 = x1 + float_tiles->levels[0].width;
y2 = y1 + float_tiles->levels[0].height;
transform_point (matrix, x1, y1, &dx1, &dy1);
transform_point (matrix, x2, y1, &dx2, &dy2);
transform_point (matrix, x1, y2, &dx3, &dy3);
transform_point (matrix, x2, y2, &dx4, &dy4);
/* Find the bounding coordinates */
tx1 = MINIMUM (dx1, dx2);
tx1 = MINIMUM (tx1, dx3);
tx1 = MINIMUM (tx1, dx4);
ty1 = MINIMUM (dy1, dy2);
ty1 = MINIMUM (ty1, dy3);
ty1 = MINIMUM (ty1, dy4);
tx2 = MAXIMUM (dx1, dx2);
tx2 = MAXIMUM (tx2, dx3);
tx2 = MAXIMUM (tx2, dx4);
ty2 = MAXIMUM (dy1, dy2);
ty2 = MAXIMUM (ty2, dy3);
ty2 = MAXIMUM (ty2, dy4);
if (active_tool && active_tool->type == PERSPECTIVE && transform_tool_clip ())
{
tx1 = x1;
ty1 = y1;
tx2 = x2;
ty2 = y2;
}
else
{
double dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4;
transform_point (matrix, x1, y1, &dx1, &dy1);
transform_point (matrix, x2, y1, &dx2, &dy2);
transform_point (matrix, x1, y2, &dx3, &dy3);
transform_point (matrix, x2, y2, &dx4, &dy4);
tx1 = MINIMUM (dx1, dx2);
tx1 = MINIMUM (tx1, dx3);
tx1 = MINIMUM (tx1, dx4);
ty1 = MINIMUM (dy1, dy2);
ty1 = MINIMUM (ty1, dy3);
ty1 = MINIMUM (ty1, dy4);
tx2 = MAXIMUM (dx1, dx2);
tx2 = MAXIMUM (tx2, dx3);
tx2 = MAXIMUM (tx2, dx4);
ty2 = MAXIMUM (dy1, dy2);
ty2 = MAXIMUM (ty2, dy3);
ty2 = MAXIMUM (ty2, dy4);
}
/* Get the new temporary buffer for the transformed result */
tiles = tile_manager_new ((tx2 - tx1), (ty2 - ty1), float_tiles->levels[0].bpp);

View File

@ -28,6 +28,7 @@
#define HANDLE_2 2
#define HANDLE_3 3
#define HANDLE_4 4
#define HANDLE_CENTER 5
/* the different states that the transformation function can be called with */
#define INIT 0
@ -36,7 +37,7 @@
#define FINISH 3
/* buffer sizes for scaling information strings (for the info dialog) */
#define MAX_INFO_BUF 12
#define MAX_INFO_BUF 40
#define TRAN_INFO_SIZE 8
/* control whether the transform tool draws a bounding box */
@ -68,16 +69,19 @@ struct _transform_core
int x1, y1; /* upper left hand coordinate */
int x2, y2; /* lower right hand coords */
int cx, cy; /* center point (for rotation) */
double tx1, ty1; /* transformed coords */
double tx2, ty2; /* */
double tx3, ty3; /* */
double tx4, ty4; /* */
double tcx, tcy; /* */
int sx1, sy1; /* transformed screen coords */
int sx2, sy2; /* position of four handles */
int sx3, sy3; /* */
int sx4, sy4; /* */
int scx, scy; /* and center for rotation */
Matrix transform; /* transformation matrix */
TranInfo trans_info; /* transformation info */
@ -93,8 +97,6 @@ struct _transform_core
* a button pressed before we deal with
* motion events. ALT.
*/
/* The following fields are used by
the "new UI". */
int ngx, ngy; /* number of grid lines in original
x and y directions */
double *grid_coords; /* x and y coordinates of the grid
@ -112,7 +114,6 @@ struct _transform_undo
int tool_ID;
int tool_type;
TranInfo trans_info;
int first;
TileManager * original;
};
@ -133,6 +134,7 @@ void transform_core_no_draw (Tool *);
Tool * transform_core_new (int, int);
void transform_core_free (Tool *);
void transform_core_reset (Tool *, void *);
void transform_core_grid_density_changed (void);
/* transform functions */
TileManager * transform_core_do (GImage *, GimpDrawable *, TileManager *, int, Matrix);

View File

@ -16,6 +16,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <math.h>
#include "appenv.h"
#include "gdisplay.h"
#include "tools.h"
@ -23,14 +24,16 @@
#include "rotate_tool.h"
#include "scale_tool.h"
#include "shear_tool.h"
#include "transform_core.h"
#include "transform_tool.h"
typedef struct _TransformOptions TransformOptions;
struct _TransformOptions
{
int direction;
int smoothing;
int new_ui;
int clip;
int grid_size;
ToolType type;
};
@ -41,7 +44,6 @@ static void transform_change_type (int);
/* Static variables */
static TransformOptions *transform_options = NULL;
static void
transform_toggle_update (GtkWidget *w,
gpointer data)
@ -63,31 +65,62 @@ transform_type_callback (GtkWidget *w,
transform_change_type ((long) client_data);
}
static void
transform_direction_callback (GtkWidget *w,
gpointer client_data)
{
long dir = (long) client_data;
if (dir == TRANSFORM_TRADITIONAL)
transform_options->direction = TRANSFORM_TRADITIONAL;
else
transform_options->direction = TRANSFORM_CORRECTIVE;
}
static void
transform_grid_density_callback (GtkWidget *w,
GtkSpinButton *spin)
{
transform_options->grid_size =
(int) pow (2.0, 7.0 - gtk_spin_button_get_value_as_int (spin));
transform_core_grid_density_changed ();
}
static TransformOptions *
create_transform_options (void)
{
TransformOptions *options;
GtkWidget *vbox;
GtkWidget *vbox, *hbox;
GtkWidget *label;
GtkWidget *radio_frame;
GtkWidget *radio_box;
GtkWidget *radio_button;
GtkWidget *smoothing_toggle;
GtkWidget *new_ui_toggle;
GSList *group = NULL;
GtkWidget *clip_toggle;
GtkAdjustment *grid_adj;
GtkWidget *grid_density;
GSList *group;
int i;
char *button_names[4] =
char *transform_button_names[4] =
{
"Rotation",
"Scaling",
"Shearing",
"Perspective"
};
char *direction_button_names[2] =
{
"Corrective",
"Traditional"
};
/* the new options structure */
options = (TransformOptions *) g_malloc (sizeof (TransformOptions));
options->smoothing = 1;
options->type = ROTATE;
options->smoothing = 1;
options->clip = 1;
options->direction = TRANSFORM_CORRECTIVE;
options->grid_size = 32;
/* the main vbox */
vbox = gtk_vbox_new (FALSE, 1);
@ -97,22 +130,47 @@ create_transform_options (void)
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
/* the radio frame and box */
/* the first radio frame and box, for transform type */
radio_frame = gtk_frame_new ("Transform");
gtk_box_pack_start (GTK_BOX (vbox), radio_frame, FALSE, FALSE, 0);
radio_box = gtk_vbox_new (FALSE, 1);
gtk_container_add (GTK_CONTAINER (radio_frame), radio_box);
/* the radio buttons */
group = NULL;
for (i = 0; i < 4; i++)
{
radio_button =
gtk_radio_button_new_with_label (group, transform_button_names[i]);
group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio_button));
gtk_box_pack_start (GTK_BOX (radio_box), radio_button, FALSE, FALSE, 0);
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
(GtkSignalFunc) transform_type_callback,
(gpointer) ((long) ROTATE + i));
gtk_widget_show (radio_button);
}
gtk_widget_show (radio_box);
gtk_widget_show (radio_frame);
/* the second radio frame and box, for transform direction */
radio_frame = gtk_frame_new ("Tool paradigm");
gtk_box_pack_start (GTK_BOX (vbox), radio_frame, FALSE, FALSE, 0);
radio_box = gtk_vbox_new (FALSE, 1);
gtk_container_add (GTK_CONTAINER (radio_frame), radio_box);
/* the radio buttons */
for (i = 0; i < 4; i++)
group = NULL;
for (i = 0; i < 2; i++)
{
radio_button = gtk_radio_button_new_with_label (group, button_names[i]);
radio_button =
gtk_radio_button_new_with_label (group, direction_button_names[i]);
group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio_button));
gtk_box_pack_start (GTK_BOX (radio_box), radio_button, FALSE, FALSE, 0);
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
(GtkSignalFunc) transform_type_callback,
(gpointer) ((long) ROTATE + i));
(GtkSignalFunc) transform_direction_callback,
(gpointer) ((long) i));
gtk_widget_show (radio_button);
}
gtk_widget_show (radio_box);
@ -128,19 +186,32 @@ create_transform_options (void)
options->smoothing);
gtk_widget_show (smoothing_toggle);
/* the new UI toggle button */
new_ui_toggle = gtk_check_button_new_with_label ("New user interface");
gtk_box_pack_start (GTK_BOX (vbox), new_ui_toggle, FALSE, FALSE, 0);
gtk_signal_connect (GTK_OBJECT (new_ui_toggle), "toggled",
/* the clip resulting image toggle button */
clip_toggle = gtk_check_button_new_with_label ("Clip perspective");
gtk_box_pack_start (GTK_BOX (vbox), clip_toggle, FALSE, FALSE, 0);
gtk_signal_connect (GTK_OBJECT (clip_toggle), "toggled",
(GtkSignalFunc) transform_toggle_update,
&options->new_ui);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (new_ui_toggle),
options->new_ui);
gtk_widget_show (new_ui_toggle);
&options->clip);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (clip_toggle),
options->clip);
gtk_widget_show (clip_toggle);
/* the grid size entry */
options->grid_size = 32; /* XXX */
/* the grid density entry */
hbox = gtk_hbox_new (FALSE, 1);
gtk_widget_show (hbox);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new ("Grid density: ");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
grid_adj = (GtkAdjustment *) gtk_adjustment_new (2.0, 0.0, 5.0, 1.0, 1.0, 0.0);
grid_density = gtk_spin_button_new (grid_adj, 0, 0);
gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (grid_density), TRUE);
gtk_signal_connect (GTK_OBJECT (grid_adj), "value_changed",
(GtkSignalFunc) transform_grid_density_callback,
grid_density);
gtk_box_pack_start (GTK_BOX (hbox), grid_density, FALSE, FALSE, 0);
gtk_widget_show (grid_density);
/* Register this selection options widget with the main tools options dialog */
tools_register_options (ROTATE, vbox);
@ -221,12 +292,21 @@ transform_tool_smoothing ()
}
int
transform_tool_new_ui ()
transform_tool_clip ()
{
if (!transform_options)
return 1;
return 0;
else
return transform_options->new_ui;
return transform_options->clip;
}
int
transform_tool_direction ()
{
if (!transform_options)
return TRANSFORM_TRADITIONAL;
else
return transform_options->direction;
}
int

View File

@ -22,7 +22,12 @@
Tool * tools_new_transform_tool (void);
void tools_free_transform_tool (Tool *);
int transform_tool_smoothing (void);
int transform_tool_new_ui (void);
int transform_tool_clip (void);
int transform_tool_direction (void);
int transform_tool_grid_size (void);
/* transform directions */
#define TRANSFORM_CORRECTIVE 0
#define TRANSFORM_TRADITIONAL 1
#endif /* __TRANSFORM_TOOL_H__ */

View File

@ -18,6 +18,7 @@
#include <stdlib.h>
#include <math.h>
#include "appenv.h"
#include "actionarea.h"
#include "drawable.h"
#include "errors.h"
#include "floating_sel.h"
@ -48,7 +49,6 @@
/* variables */
static TranInfo old_trans_info;
static int new_ui;
InfoDialog * transform_info = NULL;
/* forward function declarations */
@ -68,6 +68,52 @@ static void invert (Matrix, Matrix);
src[i] = tile_data_pointer (tile[i], (x) % TILE_WIDTH, (y) % TILE_HEIGHT);
static void
transform_ok_callback (GtkWidget *w,
gpointer client_data)
{
Tool *tool;
tool = (Tool *) client_data;
transform_core_doit (tool, tool->gdisp_ptr);
}
static void
transform_cancel_callback (GtkWidget *w,
gpointer client_data)
{
Tool *tool;
TransformCore *transform_core;
int i;
tool = (Tool *) client_data;
transform_core = (TransformCore *) tool->private;
/* stop the current tool drawing process */
draw_core_pause (transform_core->core, tool);
/* Restore the previous transformation info */
for (i = 0; i < TRAN_INFO_SIZE; i++)
transform_core->trans_info [i] = old_trans_info [i];
/* recalculate the tool's transformation matrix */
transform_core_recalc (tool, tool->gdisp_ptr);
/* resume drawing the current tool */
draw_core_resume (transform_core->core, tool);
}
static ActionAreaItem action_items[2] =
{
{ NULL, transform_ok_callback, NULL, NULL },
{ "Cancel", transform_cancel_callback, NULL, NULL },
};
static char *action_labels[4] =
{
"Rotate", "Scale", "Shear", "Transform"
};
void
transform_core_button_press (tool, bevent, gdisp_ptr)
Tool *tool;
@ -90,7 +136,7 @@ transform_core_button_press (tool, bevent, gdisp_ptr)
tool->drawable = gimage_active_drawable (gdisp->gimage);
if (transform_core->function == CREATING)
if (transform_core->function == CREATING && tool->state == ACTIVE)
{
/* Save the current transformation info */
for (i = 0; i < TRAN_INFO_SIZE; i++)
@ -105,6 +151,9 @@ transform_core_button_press (tool, bevent, gdisp_ptr)
if ((transform_core->function >= CREATING) && (gdisp_ptr == tool->gdisp_ptr) &&
transform_core->interactive)
{
/* start drawing the bounding box and handles... */
draw_core_start (transform_core->core, gdisp->canvas->window, tool);
x = bevent->x;
y = bevent->y;
@ -132,6 +181,13 @@ transform_core_button_press (tool, bevent, gdisp_ptr)
transform_core->function = HANDLE_4;
}
if (tool->type == ROTATE
&& (SQR (x - transform_core->scx) +
SQR (y - transform_core->scy)) <= 100)
{
transform_core->function = HANDLE_CENTER;
}
/* Save the current pointer position */
gdisplay_untransform_coords (gdisp, bevent->x, bevent->y,
&transform_core->startx,
@ -143,10 +199,6 @@ transform_core_button_press (tool, bevent, gdisp_ptr)
GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
NULL, NULL, bevent->time);
/* start drawing the bounding box and handles... */
if (new_ui)
draw_core_start (transform_core->core, gdisp->canvas->window, tool);
tool->state = ACTIVE;
return;
}
@ -192,20 +244,24 @@ transform_core_button_press (tool, bevent, gdisp_ptr)
*/
transform_core_bounds (tool, gdisp_ptr);
/* If new UI, calculate the grid line endpoints */
if (new_ui)
transform_core_setup_grid (tool);
/* Calculate the grid line endpoints */
transform_core_setup_grid (tool);
/* Initialize the transform tool */
(* transform_core->trans_func) (tool, gdisp_ptr, INIT);
if (transform_info != NULL)
{
action_items[0].label = action_labels[tool->type - ROTATE];
action_items[0].user_data = tool;
action_items[1].user_data = tool;
build_action_area (GTK_DIALOG (transform_info->shell),
action_items, 2, 0);
}
/* Recalculate the transform tool */
transform_core_recalc (tool, gdisp_ptr);
/* start drawing the bounding box and handles... */
if (!new_ui)
draw_core_start (transform_core->core, gdisp->canvas->window, tool);
/* recall this function to find which handle we're dragging */
if (transform_core->interactive)
transform_core_button_press (tool, bevent, gdisp_ptr);
@ -239,23 +295,16 @@ transform_core_button_release (tool, bevent, gdisp_ptr)
/* if the 3rd button isn't pressed, transform the selected mask */
if (! (bevent->state & GDK_BUTTON3_MASK))
{
if (new_ui)
/* Shift-clicking is another way to approve the transform */
if ((bevent->state & GDK_SHIFT_MASK)
|| (tool->type == FLIP_HORZ)
|| (tool->type == FLIP_VERT))
{
/* In the new UI, shift-clicking means perform the transform */
if ((bevent->state & GDK_SHIFT_MASK)
|| (tool->type == FLIP_HORZ)
|| (tool->type == FLIP_VERT))
{
transform_core_doit (tool, gdisp_ptr);
}
else
{
/* Do nothing, keep the grid visible */
}
transform_core_doit (tool, gdisp_ptr);
}
else
{
transform_core_doit (tool, gdisp_ptr);
/* Do nothing, keep the grid visible */
}
}
else
@ -266,7 +315,6 @@ transform_core_button_release (tool, bevent, gdisp_ptr)
/* Restore the previous transformation info */
for (i = 0; i < TRAN_INFO_SIZE; i++)
transform_core->trans_info [i] = old_trans_info [i];
/* recalculate the tool's transformation matrix */
transform_core_recalc (tool, gdisp_ptr);
@ -288,7 +336,6 @@ transform_core_doit (tool, gdisp_ptr)
TransformCore *transform_core;
TileManager *new_tiles;
TransformUndo *tu;
int first_transform;
int new_layer;
int i, x, y;
@ -304,35 +351,25 @@ transform_core_doit (tool, gdisp_ptr)
/* Start a transform undo group */
undo_push_group_start (gdisp->gimage, TRANSFORM_CORE_UNDO);
/* If original is NULL, then this is the first transformation */
first_transform = (transform_core->original) ? FALSE : TRUE;
/* With the old UI, if original is NULL, then this is the
first transformation. In the new UI, it is always so, yes? */
g_assert (transform_core->original == NULL);
/* If we're in interactive mode, and haven't yet done any
* transformations, we need to copy the current selection to
* the transform tool's private selection pointer, so that the
* original source can be repeatedly modified.
/* If we're in interactive mode, we need to copy the current
* selection to the transform tool's private selection pointer, so
* that the original source can be repeatedly modified.
*/
if (first_transform)
transform_core->original = transform_core_cut (gdisp->gimage,
gimage_active_drawable (gdisp->gimage),
&new_layer);
else
new_layer = FALSE;
transform_core->original = transform_core_cut (gdisp->gimage,
gimage_active_drawable (gdisp->gimage),
&new_layer);
/* Send the request for the transformation to the tool...
*/
new_tiles = (* transform_core->trans_func) (tool, gdisp_ptr, FINISH);
/* If new UI, reset the transformation */
if (new_ui)
{
int i;
for (i = 0; i < TRAN_INFO_SIZE; i++)
transform_core->trans_info [i] = 0;
transform_core_recalc (tool, gdisp_ptr);
}
(* transform_core->trans_func) (tool, gdisp_ptr, INIT);
transform_core_recalc (tool, gdisp_ptr);
if (new_tiles)
{
@ -348,7 +385,6 @@ transform_core_doit (tool, gdisp_ptr)
tu->tool_type = tool->type;
for (i = 0; i < TRAN_INFO_SIZE; i++)
tu->trans_info[i] = old_trans_info[i];
tu->first = first_transform;
tu->original = NULL;
/* Make a note of the new current drawable (since we may have
@ -389,10 +425,7 @@ transform_core_doit (tool, gdisp_ptr)
}
gdisplays_flush ();
if (new_ui)
{
transform_core_reset (tool, gdisp_ptr);
}
transform_core_reset (tool, gdisp_ptr);
/* if this tool is non-interactive, make it inactive after use */
if (!transform_core->interactive)
@ -534,6 +567,8 @@ transform_core_draw (tool)
TransformCore * transform_core;
GDisplay * gdisp;
int srw, srh;
int i, k, gci;
int xa, ya, xb, yb;
gdisp = tool->gdisp_ptr;
transform_core = (TransformCore *) tool->private;
@ -566,27 +601,22 @@ transform_core_draw (tool)
gdk_draw_line (transform_core->core->win, transform_core->core->gc,
x3, y3, x1, y1);
/* if new UI, draw the grid */
if (new_ui)
{
int i, k, gci;
int xa, ya, xb, yb;
/* Draw the grid */
gci = 0;
k = transform_core->ngx + transform_core->ngy;
for (i = 0; i < k; i++)
{
gdisplay_transform_coords (gdisp, transform_core->tgrid_coords[gci],
transform_core->tgrid_coords[gci+1],
&xa, &ya, 0);
gdisplay_transform_coords (gdisp, transform_core->tgrid_coords[gci+2],
transform_core->tgrid_coords[gci+3],
&xb, &yb, 0);
gdk_draw_line (transform_core->core->win, transform_core->core->gc,
xa, ya, xb, yb);
gci += 4;
}
gci = 0;
k = transform_core->ngx + transform_core->ngy;
for (i = 0; i < k; i++)
{
gdisplay_transform_coords (gdisp, transform_core->tgrid_coords[gci],
transform_core->tgrid_coords[gci+1],
&xa, &ya, 0);
gdisplay_transform_coords (gdisp, transform_core->tgrid_coords[gci+2],
transform_core->tgrid_coords[gci+3],
&xb, &yb, 0);
gdk_draw_line (transform_core->core->win, transform_core->core->gc,
xa, ya, xb, yb);
gci += 4;
}
/* draw the tool handles */
@ -598,6 +628,18 @@ transform_core_draw (tool)
x3 - (srw >> 1), y3 - (srh >> 1), srw, srh);
gdk_draw_rectangle (transform_core->core->win, transform_core->core->gc, 0,
x4 - (srw >> 1), y4 - (srh >> 1), srw, srh);
/* draw the center */
if (tool->type == ROTATE)
{
gdisplay_transform_coords (gdisp, transform_core->tcx, transform_core->tcy,
&transform_core->scx, &transform_core->scy, 0);
gdk_draw_arc (transform_core->core->win, transform_core->core->gc, 1,
transform_core->scx - (srw >> 1),
transform_core->scy - (srh >> 1),
srw, srh, 0, 23040);
}
}
Tool *
@ -629,15 +671,6 @@ transform_core_new (type, interactive)
private->grid_coords = private->tgrid_coords = NULL;
/* We must save this setting so that the user won't screw us if he
* changes the UI to "old" style in the middle of a "new" UI operation.
* We can't keep this info in the transform_core, as it is needed
* in transform_core_do, which doesn't have access to any TransformCore.
* I hope it's OK to use a static variable... (there already is
* old_trans_info, so?).
*/
new_ui = transform_tool_new_ui ();
tool->type = type;
tool->state = INACTIVE;
tool->scroll_lock = 1; /* Do not allow scrolling */
@ -693,6 +726,8 @@ transform_bounding_box (tool)
Tool * tool;
{
TransformCore * transform_core;
int i, k;
int gci;
transform_core = (TransformCore *) tool->private;
@ -709,22 +744,21 @@ transform_bounding_box (tool)
transform_core->x2, transform_core->y2,
&transform_core->tx4, &transform_core->ty4);
if (new_ui)
if (tool->type == ROTATE)
transform_point (transform_core->transform,
transform_core->cx, transform_core->cy,
&transform_core->tcx, &transform_core->tcy);
gci = 0;
k = (transform_core->ngx + transform_core->ngy) * 2;
for (i = 0; i < k; i++)
{
int i, k;
int gci;
gci = 0;
k = (transform_core->ngx + transform_core->ngy) * 2;
for (i = 0; i < k; i++)
{
transform_point (transform_core->transform,
transform_core->grid_coords[gci],
transform_core->grid_coords[gci+1],
&(transform_core->tgrid_coords[gci]),
&(transform_core->tgrid_coords[gci+1]));
gci += 2;
}
transform_point (transform_core->transform,
transform_core->grid_coords[gci],
transform_core->grid_coords[gci+1],
&(transform_core->tgrid_coords[gci]),
&(transform_core->tgrid_coords[gci+1]));
gci += 2;
}
}
@ -973,10 +1007,26 @@ transform_core_bounds (tool, gdisp_ptr)
transform_core->x2 += offset_x;
transform_core->y2 += offset_y;
}
transform_core->cx = (transform_core->x1 + transform_core->x2) / 2;
transform_core->cy = (transform_core->y1 + transform_core->y2) / 2;
return TRUE;
}
void
transform_core_grid_density_changed ()
{
TransformCore * transform_core;
transform_core = (TransformCore *) active_tool->private;
draw_core_pause (transform_core->core, active_tool);
g_free (transform_core->grid_coords);
g_free (transform_core->tgrid_coords);
transform_core_setup_grid (active_tool);
transform_bounding_box (active_tool);
draw_core_resume (transform_core->core, active_tool);
}
static void
transform_core_setup_grid (tool)
Tool *tool;
@ -988,7 +1038,7 @@ transform_core_setup_grid (tool)
transform_core = (TransformCore *) tool->private;
/* We use the transform_tool_grid_size function only here, even if the
* user changes the grid size in the middle of a "new" UI
* user changes the grid size in the middle of a
* operation, nothing happens.
*/
transform_core->ngx =
@ -1066,7 +1116,6 @@ transform_core_do (gimage, drawable, float_tiles, interpolation, matrix)
int plus2_x, plus2_y;
int minus_x, minus_y;
int x1, y1, x2, y2;
double dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4;
double xinc, yinc, winc;
double tx, ty, tw;
double ttx = 0.0, tty = 0.0;
@ -1104,7 +1153,7 @@ transform_core_do (gimage, drawable, float_tiles, interpolation, matrix)
break;
}
if (new_ui)
if (transform_tool_direction () == TRANSFORM_CORRECTIVE)
{
invert (matrix, im);
matrix = im;
@ -1118,24 +1167,36 @@ transform_core_do (gimage, drawable, float_tiles, interpolation, matrix)
x2 = x1 + float_tiles->levels[0].width;
y2 = y1 + float_tiles->levels[0].height;
transform_point (matrix, x1, y1, &dx1, &dy1);
transform_point (matrix, x2, y1, &dx2, &dy2);
transform_point (matrix, x1, y2, &dx3, &dy3);
transform_point (matrix, x2, y2, &dx4, &dy4);
/* Find the bounding coordinates */
tx1 = MINIMUM (dx1, dx2);
tx1 = MINIMUM (tx1, dx3);
tx1 = MINIMUM (tx1, dx4);
ty1 = MINIMUM (dy1, dy2);
ty1 = MINIMUM (ty1, dy3);
ty1 = MINIMUM (ty1, dy4);
tx2 = MAXIMUM (dx1, dx2);
tx2 = MAXIMUM (tx2, dx3);
tx2 = MAXIMUM (tx2, dx4);
ty2 = MAXIMUM (dy1, dy2);
ty2 = MAXIMUM (ty2, dy3);
ty2 = MAXIMUM (ty2, dy4);
if (active_tool && active_tool->type == PERSPECTIVE && transform_tool_clip ())
{
tx1 = x1;
ty1 = y1;
tx2 = x2;
ty2 = y2;
}
else
{
double dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4;
transform_point (matrix, x1, y1, &dx1, &dy1);
transform_point (matrix, x2, y1, &dx2, &dy2);
transform_point (matrix, x1, y2, &dx3, &dy3);
transform_point (matrix, x2, y2, &dx4, &dy4);
tx1 = MINIMUM (dx1, dx2);
tx1 = MINIMUM (tx1, dx3);
tx1 = MINIMUM (tx1, dx4);
ty1 = MINIMUM (dy1, dy2);
ty1 = MINIMUM (ty1, dy3);
ty1 = MINIMUM (ty1, dy4);
tx2 = MAXIMUM (dx1, dx2);
tx2 = MAXIMUM (tx2, dx3);
tx2 = MAXIMUM (tx2, dx4);
ty2 = MAXIMUM (dy1, dy2);
ty2 = MAXIMUM (ty2, dy3);
ty2 = MAXIMUM (ty2, dy4);
}
/* Get the new temporary buffer for the transformed result */
tiles = tile_manager_new ((tx2 - tx1), (ty2 - ty1), float_tiles->levels[0].bpp);

View File

@ -28,6 +28,7 @@
#define HANDLE_2 2
#define HANDLE_3 3
#define HANDLE_4 4
#define HANDLE_CENTER 5
/* the different states that the transformation function can be called with */
#define INIT 0
@ -36,7 +37,7 @@
#define FINISH 3
/* buffer sizes for scaling information strings (for the info dialog) */
#define MAX_INFO_BUF 12
#define MAX_INFO_BUF 40
#define TRAN_INFO_SIZE 8
/* control whether the transform tool draws a bounding box */
@ -68,16 +69,19 @@ struct _transform_core
int x1, y1; /* upper left hand coordinate */
int x2, y2; /* lower right hand coords */
int cx, cy; /* center point (for rotation) */
double tx1, ty1; /* transformed coords */
double tx2, ty2; /* */
double tx3, ty3; /* */
double tx4, ty4; /* */
double tcx, tcy; /* */
int sx1, sy1; /* transformed screen coords */
int sx2, sy2; /* position of four handles */
int sx3, sy3; /* */
int sx4, sy4; /* */
int scx, scy; /* and center for rotation */
Matrix transform; /* transformation matrix */
TranInfo trans_info; /* transformation info */
@ -93,8 +97,6 @@ struct _transform_core
* a button pressed before we deal with
* motion events. ALT.
*/
/* The following fields are used by
the "new UI". */
int ngx, ngy; /* number of grid lines in original
x and y directions */
double *grid_coords; /* x and y coordinates of the grid
@ -112,7 +114,6 @@ struct _transform_undo
int tool_ID;
int tool_type;
TranInfo trans_info;
int first;
TileManager * original;
};
@ -133,6 +134,7 @@ void transform_core_no_draw (Tool *);
Tool * transform_core_new (int, int);
void transform_core_free (Tool *);
void transform_core_reset (Tool *, void *);
void transform_core_grid_density_changed (void);
/* transform functions */
TileManager * transform_core_do (GImage *, GimpDrawable *, TileManager *, int, Matrix);

View File

@ -16,6 +16,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <math.h>
#include "appenv.h"
#include "gdisplay.h"
#include "tools.h"
@ -23,14 +24,16 @@
#include "rotate_tool.h"
#include "scale_tool.h"
#include "shear_tool.h"
#include "transform_core.h"
#include "transform_tool.h"
typedef struct _TransformOptions TransformOptions;
struct _TransformOptions
{
int direction;
int smoothing;
int new_ui;
int clip;
int grid_size;
ToolType type;
};
@ -41,7 +44,6 @@ static void transform_change_type (int);
/* Static variables */
static TransformOptions *transform_options = NULL;
static void
transform_toggle_update (GtkWidget *w,
gpointer data)
@ -63,31 +65,62 @@ transform_type_callback (GtkWidget *w,
transform_change_type ((long) client_data);
}
static void
transform_direction_callback (GtkWidget *w,
gpointer client_data)
{
long dir = (long) client_data;
if (dir == TRANSFORM_TRADITIONAL)
transform_options->direction = TRANSFORM_TRADITIONAL;
else
transform_options->direction = TRANSFORM_CORRECTIVE;
}
static void
transform_grid_density_callback (GtkWidget *w,
GtkSpinButton *spin)
{
transform_options->grid_size =
(int) pow (2.0, 7.0 - gtk_spin_button_get_value_as_int (spin));
transform_core_grid_density_changed ();
}
static TransformOptions *
create_transform_options (void)
{
TransformOptions *options;
GtkWidget *vbox;
GtkWidget *vbox, *hbox;
GtkWidget *label;
GtkWidget *radio_frame;
GtkWidget *radio_box;
GtkWidget *radio_button;
GtkWidget *smoothing_toggle;
GtkWidget *new_ui_toggle;
GSList *group = NULL;
GtkWidget *clip_toggle;
GtkAdjustment *grid_adj;
GtkWidget *grid_density;
GSList *group;
int i;
char *button_names[4] =
char *transform_button_names[4] =
{
"Rotation",
"Scaling",
"Shearing",
"Perspective"
};
char *direction_button_names[2] =
{
"Corrective",
"Traditional"
};
/* the new options structure */
options = (TransformOptions *) g_malloc (sizeof (TransformOptions));
options->smoothing = 1;
options->type = ROTATE;
options->smoothing = 1;
options->clip = 1;
options->direction = TRANSFORM_CORRECTIVE;
options->grid_size = 32;
/* the main vbox */
vbox = gtk_vbox_new (FALSE, 1);
@ -97,22 +130,47 @@ create_transform_options (void)
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
/* the radio frame and box */
/* the first radio frame and box, for transform type */
radio_frame = gtk_frame_new ("Transform");
gtk_box_pack_start (GTK_BOX (vbox), radio_frame, FALSE, FALSE, 0);
radio_box = gtk_vbox_new (FALSE, 1);
gtk_container_add (GTK_CONTAINER (radio_frame), radio_box);
/* the radio buttons */
group = NULL;
for (i = 0; i < 4; i++)
{
radio_button =
gtk_radio_button_new_with_label (group, transform_button_names[i]);
group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio_button));
gtk_box_pack_start (GTK_BOX (radio_box), radio_button, FALSE, FALSE, 0);
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
(GtkSignalFunc) transform_type_callback,
(gpointer) ((long) ROTATE + i));
gtk_widget_show (radio_button);
}
gtk_widget_show (radio_box);
gtk_widget_show (radio_frame);
/* the second radio frame and box, for transform direction */
radio_frame = gtk_frame_new ("Tool paradigm");
gtk_box_pack_start (GTK_BOX (vbox), radio_frame, FALSE, FALSE, 0);
radio_box = gtk_vbox_new (FALSE, 1);
gtk_container_add (GTK_CONTAINER (radio_frame), radio_box);
/* the radio buttons */
for (i = 0; i < 4; i++)
group = NULL;
for (i = 0; i < 2; i++)
{
radio_button = gtk_radio_button_new_with_label (group, button_names[i]);
radio_button =
gtk_radio_button_new_with_label (group, direction_button_names[i]);
group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio_button));
gtk_box_pack_start (GTK_BOX (radio_box), radio_button, FALSE, FALSE, 0);
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
(GtkSignalFunc) transform_type_callback,
(gpointer) ((long) ROTATE + i));
(GtkSignalFunc) transform_direction_callback,
(gpointer) ((long) i));
gtk_widget_show (radio_button);
}
gtk_widget_show (radio_box);
@ -128,19 +186,32 @@ create_transform_options (void)
options->smoothing);
gtk_widget_show (smoothing_toggle);
/* the new UI toggle button */
new_ui_toggle = gtk_check_button_new_with_label ("New user interface");
gtk_box_pack_start (GTK_BOX (vbox), new_ui_toggle, FALSE, FALSE, 0);
gtk_signal_connect (GTK_OBJECT (new_ui_toggle), "toggled",
/* the clip resulting image toggle button */
clip_toggle = gtk_check_button_new_with_label ("Clip perspective");
gtk_box_pack_start (GTK_BOX (vbox), clip_toggle, FALSE, FALSE, 0);
gtk_signal_connect (GTK_OBJECT (clip_toggle), "toggled",
(GtkSignalFunc) transform_toggle_update,
&options->new_ui);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (new_ui_toggle),
options->new_ui);
gtk_widget_show (new_ui_toggle);
&options->clip);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (clip_toggle),
options->clip);
gtk_widget_show (clip_toggle);
/* the grid size entry */
options->grid_size = 32; /* XXX */
/* the grid density entry */
hbox = gtk_hbox_new (FALSE, 1);
gtk_widget_show (hbox);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new ("Grid density: ");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
grid_adj = (GtkAdjustment *) gtk_adjustment_new (2.0, 0.0, 5.0, 1.0, 1.0, 0.0);
grid_density = gtk_spin_button_new (grid_adj, 0, 0);
gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (grid_density), TRUE);
gtk_signal_connect (GTK_OBJECT (grid_adj), "value_changed",
(GtkSignalFunc) transform_grid_density_callback,
grid_density);
gtk_box_pack_start (GTK_BOX (hbox), grid_density, FALSE, FALSE, 0);
gtk_widget_show (grid_density);
/* Register this selection options widget with the main tools options dialog */
tools_register_options (ROTATE, vbox);
@ -221,12 +292,21 @@ transform_tool_smoothing ()
}
int
transform_tool_new_ui ()
transform_tool_clip ()
{
if (!transform_options)
return 1;
return 0;
else
return transform_options->new_ui;
return transform_options->clip;
}
int
transform_tool_direction ()
{
if (!transform_options)
return TRANSFORM_TRADITIONAL;
else
return transform_options->direction;
}
int

View File

@ -22,7 +22,12 @@
Tool * tools_new_transform_tool (void);
void tools_free_transform_tool (Tool *);
int transform_tool_smoothing (void);
int transform_tool_new_ui (void);
int transform_tool_clip (void);
int transform_tool_direction (void);
int transform_tool_grid_size (void);
/* transform directions */
#define TRANSFORM_CORRECTIVE 0
#define TRANSFORM_TRADITIONAL 1
#endif /* __TRANSFORM_TOOL_H__ */

View File

@ -937,21 +937,17 @@ undo_pop_transform (GImage *gimage,
tc->trans_info[i] = d;
}
/* if this is the first transform in a string, swap the
* original buffer--the source buffer for repeated transforms
/* swap the original buffer--the source buffer for repeated transforms
*/
if (tu->first)
{
temp = tu->original;
tu->original = tc->original;
tc->original = temp;
temp = tu->original;
tu->original = tc->original;
tc->original = temp;
/* If we're re-implementing the first transform, reactivate tool */
if (state == REDO && tc->original)
{
active_tool->state = ACTIVE;
draw_core_resume (tc->core, active_tool);
}
/* If we're re-implementing the first transform, reactivate tool */
if (state == REDO && tc->original)
{
active_tool->state = ACTIVE;
draw_core_resume (tc->core, active_tool);
}
return TRUE;