mirror of https://github.com/GNOME/gimp.git
892 lines
26 KiB
C
892 lines
26 KiB
C
/* The GIMP -- an image manipulation program
|
|
*
|
|
* This file Copyright (C) 1999 Simon Budig
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "libgimpmath/gimpmath.h"
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
|
|
|
#include "tools-types.h"
|
|
|
|
#include "core/gimpimage.h"
|
|
|
|
#include "display/gimpdisplay.h"
|
|
#include "display/gimpdisplayshell.h"
|
|
|
|
#include "gimppathtool.h"
|
|
#include "path_tool.h"
|
|
|
|
#include "gimprc.h"
|
|
#include "path_curves.h"
|
|
|
|
#include "libgimp/gimpintl.h"
|
|
|
|
|
|
/* local function prototypes */
|
|
|
|
static void gimp_path_tool_class_init (GimpPathToolClass *klass);
|
|
static void gimp_path_tool_init (GimpPathTool *tool);
|
|
|
|
static void gimp_path_tool_finalize (GObject *object);
|
|
|
|
static void gimp_path_tool_control (GimpTool *tool,
|
|
GimpToolAction action,
|
|
GimpDisplay *gdisp);
|
|
|
|
static void gimp_path_tool_button_press (GimpTool *tool,
|
|
GimpCoords *coords,
|
|
guint32 time,
|
|
GdkModifierType state,
|
|
GimpDisplay *gdisp);
|
|
static gint gimp_path_tool_button_press_canvas (GimpPathTool *tool,
|
|
guint32 time,
|
|
GimpDisplay *gdisp);
|
|
static gint gimp_path_tool_button_press_anchor (GimpPathTool *tool,
|
|
guint32 time,
|
|
GimpDisplay *gdisp);
|
|
static gint gimp_path_tool_button_press_handle (GimpPathTool *tool,
|
|
guint32 time,
|
|
GimpDisplay *gdisp);
|
|
static gint gimp_path_tool_button_press_curve (GimpPathTool *tool,
|
|
guint32 time,
|
|
GimpDisplay *gdisp);
|
|
|
|
static void gimp_path_tool_button_release (GimpTool *tool,
|
|
GimpCoords *coords,
|
|
guint32 time,
|
|
GdkModifierType state,
|
|
GimpDisplay *gdisp);
|
|
|
|
static void gimp_path_tool_motion (GimpTool *tool,
|
|
GimpCoords *coords,
|
|
guint32 time,
|
|
GdkModifierType state,
|
|
GimpDisplay *gdisp);
|
|
static void gimp_path_tool_motion_anchor (GimpPathTool *path_tool,
|
|
GimpCoords *coords,
|
|
GdkModifierType state,
|
|
GimpDisplay *gdisp);
|
|
static void gimp_path_tool_motion_handle (GimpPathTool *path_tool,
|
|
GimpCoords *coords,
|
|
GdkModifierType state,
|
|
GimpDisplay *gdisp);
|
|
static void gimp_path_tool_motion_curve (GimpPathTool *path_tool,
|
|
GimpCoords *coords,
|
|
GdkModifierType state,
|
|
GimpDisplay *gdisp);
|
|
|
|
static void gimp_path_tool_cursor_update (GimpTool *tool,
|
|
GimpCoords *coords,
|
|
GdkModifierType state,
|
|
GimpDisplay *gdisp);
|
|
|
|
static void gimp_path_tool_draw (GimpDrawTool *draw_tool);
|
|
|
|
|
|
|
|
static GimpDrawToolClass *parent_class = NULL;
|
|
|
|
|
|
void
|
|
gimp_path_tool_register (GimpToolRegisterCallback callback,
|
|
gpointer data)
|
|
{
|
|
(* callback) (GIMP_TYPE_PATH_TOOL,
|
|
NULL,
|
|
FALSE,
|
|
"gimp-path-tool",
|
|
_("Path Tool"),
|
|
_("Path tool prototype"),
|
|
N_("/Tools/Path"), NULL,
|
|
NULL, "tools/path.html",
|
|
GIMP_STOCK_TOOL_PATH,
|
|
data);
|
|
}
|
|
|
|
GType
|
|
gimp_path_tool_get_type (void)
|
|
{
|
|
static GType tool_type = 0;
|
|
|
|
if (! tool_type)
|
|
{
|
|
static const GTypeInfo tool_info =
|
|
{
|
|
sizeof (GimpPathToolClass),
|
|
(GBaseInitFunc) NULL,
|
|
(GBaseFinalizeFunc) NULL,
|
|
(GClassInitFunc) gimp_path_tool_class_init,
|
|
NULL, /* class_finalize */
|
|
NULL, /* class_data */
|
|
sizeof (GimpPathTool),
|
|
0, /* n_preallocs */
|
|
(GInstanceInitFunc) gimp_path_tool_init,
|
|
};
|
|
|
|
tool_type = g_type_register_static (GIMP_TYPE_DRAW_TOOL,
|
|
"GimpPathTool",
|
|
&tool_info, 0);
|
|
}
|
|
|
|
return tool_type;
|
|
}
|
|
|
|
static void
|
|
gimp_path_tool_class_init (GimpPathToolClass *klass)
|
|
{
|
|
GObjectClass *object_class;
|
|
GimpToolClass *tool_class;
|
|
GimpDrawToolClass *draw_tool_class;
|
|
|
|
object_class = G_OBJECT_CLASS (klass);
|
|
tool_class = GIMP_TOOL_CLASS (klass);
|
|
draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass);
|
|
|
|
parent_class = g_type_class_peek_parent (klass);
|
|
|
|
object_class->finalize = gimp_path_tool_finalize;
|
|
|
|
tool_class->control = gimp_path_tool_control;
|
|
tool_class->button_press = gimp_path_tool_button_press;
|
|
tool_class->button_release = gimp_path_tool_button_release;
|
|
tool_class->motion = gimp_path_tool_motion;
|
|
tool_class->cursor_update = gimp_path_tool_cursor_update;
|
|
|
|
draw_tool_class->draw = gimp_path_tool_draw;
|
|
}
|
|
|
|
static void
|
|
gimp_path_tool_init (GimpPathTool *path_tool)
|
|
{
|
|
GimpTool *tool;
|
|
|
|
tool = GIMP_TOOL (path_tool);
|
|
|
|
path_tool->click_type = ON_CANVAS;
|
|
path_tool->click_x = 0;
|
|
path_tool->click_y = 0;
|
|
path_tool->click_halfwidth = 0;
|
|
path_tool->click_modifier = 0;
|
|
path_tool->click_path = NULL;
|
|
path_tool->click_curve = NULL;
|
|
path_tool->click_segment = NULL;
|
|
path_tool->click_position = -1;
|
|
|
|
path_tool->active_count = 0;
|
|
path_tool->single_active_segment = NULL;
|
|
|
|
path_tool->state = 0;
|
|
path_tool->draw = PATH_TOOL_REDRAW_ALL;
|
|
path_tool->cur_path = g_new0 (NPath, 1);
|
|
path_tool->scanlines = NULL;
|
|
|
|
|
|
/* Initial Path */
|
|
path_tool->cur_path->curves = NULL;
|
|
path_tool->cur_path->cur_curve = NULL;
|
|
path_tool->cur_path->name = g_string_new ("Path 0");
|
|
path_tool->cur_path->state = 0;
|
|
/* path_tool->cur_path->path_tool = path_tool; */
|
|
|
|
}
|
|
|
|
static void
|
|
gimp_path_tool_finalize (GObject *object)
|
|
{
|
|
GimpPathTool *path_tool;
|
|
|
|
path_tool = GIMP_PATH_TOOL (object);
|
|
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("gimp_path_tool_free start\n");
|
|
#endif
|
|
|
|
if (path_tool->cur_path)
|
|
{
|
|
path_free_path (path_tool->cur_path);
|
|
path_tool->cur_path = NULL;
|
|
}
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gimp_path_tool_control (GimpTool *tool,
|
|
GimpToolAction action,
|
|
GimpDisplay *gdisp)
|
|
{
|
|
GimpPathTool *path_tool;
|
|
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("path_tool_control\n");
|
|
#endif
|
|
|
|
path_tool = GIMP_PATH_TOOL (tool);
|
|
|
|
switch (action)
|
|
{
|
|
case PAUSE:
|
|
break;
|
|
|
|
case RESUME:
|
|
break;
|
|
|
|
case HALT:
|
|
gimp_tool_control_halt (tool->control); /* sets paused_count to 0 -- is this ok? */
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
|
|
}
|
|
|
|
static void
|
|
gimp_path_tool_button_press (GimpTool *tool,
|
|
GimpCoords *coords,
|
|
guint32 time,
|
|
GdkModifierType state,
|
|
GimpDisplay *gdisp)
|
|
{
|
|
GimpPathTool *path_tool;
|
|
GimpDisplayShell *shell;
|
|
gint grab_pointer = 0;
|
|
gint halfwidth, halfheight;
|
|
|
|
path_tool = GIMP_PATH_TOOL (tool);
|
|
|
|
shell = GIMP_DISPLAY_SHELL (gdisp->shell);
|
|
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("path_tool_button_press\n");
|
|
#endif
|
|
|
|
path_tool->click_x = coords->x;
|
|
path_tool->click_y = coords->y;
|
|
path_tool->click_modifier = state;
|
|
|
|
/* get halfwidth in image coord */
|
|
halfwidth = UNSCALEX (shell, PATH_TOOL_HALFWIDTH);
|
|
halfheight = UNSCALEY (shell, PATH_TOOL_HALFWIDTH);
|
|
|
|
path_tool->click_halfwidth = halfwidth;
|
|
path_tool->click_halfheight = halfheight;
|
|
|
|
tool->gdisp = gdisp;
|
|
gimp_tool_control_activate (tool->control);
|
|
|
|
if (! path_tool->cur_path->curves)
|
|
gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), gdisp);
|
|
|
|
/* determine point, where clicked,
|
|
* switch accordingly.
|
|
*/
|
|
|
|
path_tool->click_type =
|
|
path_tool_cursor_position (path_tool->cur_path,
|
|
coords->x,
|
|
coords->y,
|
|
halfwidth,
|
|
halfheight,
|
|
&path_tool->click_path,
|
|
&path_tool->click_curve,
|
|
&path_tool->click_segment,
|
|
&path_tool->click_position,
|
|
&path_tool->click_handle_id);
|
|
|
|
switch (path_tool->click_type)
|
|
{
|
|
case ON_CANVAS:
|
|
grab_pointer = gimp_path_tool_button_press_canvas (path_tool, time, gdisp);
|
|
break;
|
|
|
|
case ON_ANCHOR:
|
|
grab_pointer = gimp_path_tool_button_press_anchor (path_tool, time, gdisp);
|
|
break;
|
|
|
|
case ON_HANDLE:
|
|
grab_pointer = gimp_path_tool_button_press_handle (path_tool, time, gdisp);
|
|
break;
|
|
|
|
case ON_CURVE:
|
|
grab_pointer = gimp_path_tool_button_press_curve (path_tool, time, gdisp);
|
|
break;
|
|
|
|
default:
|
|
g_message ("Huh? Whats happening here? (button_press_*)");
|
|
}
|
|
}
|
|
|
|
static gint
|
|
gimp_path_tool_button_press_anchor (GimpPathTool *path_tool,
|
|
guint32 time,
|
|
GimpDisplay *gdisp)
|
|
{
|
|
static guint32 last_click_time=0;
|
|
gboolean doubleclick=FALSE;
|
|
|
|
NPath * cur_path = path_tool->cur_path;
|
|
PathSegment *p_sas;
|
|
gint grab_pointer;
|
|
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("path_tool_button_press_anchor:\n");
|
|
#endif
|
|
|
|
grab_pointer = 1;
|
|
|
|
if (!cur_path) {
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("Fatal error: No current Path\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* We have to determine, if this was a doubleclick for ourself, because
|
|
* disp_callback.c ignores the GDK_[23]BUTTON_EVENT's and adding them to
|
|
* the switch statement confuses some tools.
|
|
*/
|
|
if (time - last_click_time < 250) {
|
|
doubleclick=TRUE;
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("Doppelclick!\n");
|
|
#endif
|
|
} else
|
|
doubleclick=FALSE;
|
|
last_click_time = time;
|
|
|
|
|
|
gimp_draw_tool_pause (GIMP_DRAW_TOOL(path_tool));
|
|
|
|
/* The user pressed on an anchor:
|
|
* normally this activates this anchor
|
|
* + SHIFT toggles the activity of an anchor.
|
|
* if this anchor is at the end of an open curve and the other
|
|
* end is active, close the curve.
|
|
*
|
|
* Doubleclick (de)activates the whole curve (not Path!).
|
|
*/
|
|
|
|
p_sas = path_tool->single_active_segment;
|
|
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("p_sas: %p\n", p_sas);
|
|
#endif
|
|
|
|
if (path_tool->click_modifier & GDK_SHIFT_MASK) {
|
|
if (path_tool->active_count == 1 && p_sas && p_sas != path_tool->click_segment &&
|
|
(p_sas->next == NULL || p_sas->prev == NULL) &&
|
|
(path_tool->click_segment->next == NULL || path_tool->click_segment->prev == NULL)) {
|
|
/*
|
|
* if this is the end of an open curve and the single active segment was another
|
|
* open end, connect those ends.
|
|
*/
|
|
path_join_curves (path_tool->click_segment, p_sas);
|
|
path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
|
|
NULL, 0, SEGMENT_ACTIVE);
|
|
}
|
|
|
|
if (doubleclick)
|
|
/*
|
|
* Doubleclick set the whole curve to the same state, depending on the
|
|
* state of the clicked anchor.
|
|
*/
|
|
if (path_tool->click_segment->flags & SEGMENT_ACTIVE)
|
|
path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
|
|
NULL, SEGMENT_ACTIVE, 0);
|
|
else
|
|
path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
|
|
NULL, 0, SEGMENT_ACTIVE);
|
|
else
|
|
/*
|
|
* Toggle the state of the clicked anchor.
|
|
*/
|
|
if (path_tool->click_segment->flags & SEGMENT_ACTIVE)
|
|
path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
|
|
path_tool->click_segment, 0, SEGMENT_ACTIVE);
|
|
else
|
|
path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
|
|
path_tool->click_segment, SEGMENT_ACTIVE, 0);
|
|
}
|
|
/*
|
|
* Delete anchors, when CONTROL is pressed
|
|
*/
|
|
else if (path_tool->click_modifier & GDK_CONTROL_MASK)
|
|
{
|
|
if (path_tool->click_segment->flags & SEGMENT_ACTIVE)
|
|
{
|
|
if (path_tool->click_segment->prev)
|
|
path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
|
|
path_tool->click_segment->prev, SEGMENT_ACTIVE, 0);
|
|
else if (path_tool->click_segment->next)
|
|
path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
|
|
path_tool->click_segment->next, SEGMENT_ACTIVE, 0);
|
|
}
|
|
|
|
path_delete_segment (path_tool->click_segment);
|
|
path_tool->click_segment = NULL;
|
|
/* Maybe CTRL-ALT Click should remove the whole curve? Or the active points? */
|
|
}
|
|
else if (!(path_tool->click_segment->flags & SEGMENT_ACTIVE))
|
|
{
|
|
path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
|
|
path_set_flags (path_tool, cur_path, path_tool->click_curve, path_tool->click_segment, SEGMENT_ACTIVE, 0);
|
|
}
|
|
|
|
|
|
gimp_draw_tool_resume (GIMP_DRAW_TOOL(path_tool));
|
|
|
|
return grab_pointer;
|
|
}
|
|
|
|
|
|
static gint
|
|
gimp_path_tool_button_press_handle (GimpPathTool *path_tool,
|
|
guint32 time,
|
|
GimpDisplay *gdisp)
|
|
{
|
|
static guint32 last_click_time=0;
|
|
gboolean doubleclick=FALSE;
|
|
|
|
NPath * cur_path = path_tool->cur_path;
|
|
gint grab_pointer;
|
|
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("path_tool_button_press_handle:\n");
|
|
#endif
|
|
|
|
grab_pointer = 1;
|
|
|
|
if (!cur_path) {
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("Fatal error: No current Path\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/* gint click_halfwidth;
|
|
|
|
* We have to determine, if this was a doubleclick for ourself, because
|
|
* disp_callback.c ignores the GDK_[23]BUTTON_EVENT's and adding them to
|
|
* the switch statement confuses some tools.
|
|
*/
|
|
if (time - last_click_time < 250) {
|
|
doubleclick=TRUE;
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("Doppelclick!\n");
|
|
#endif
|
|
} else
|
|
doubleclick=FALSE;
|
|
last_click_time = time;
|
|
|
|
return grab_pointer;
|
|
}
|
|
|
|
static gint
|
|
gimp_path_tool_button_press_canvas (GimpPathTool *path_tool,
|
|
guint32 time,
|
|
GimpDisplay *gdisp)
|
|
{
|
|
NPath * cur_path = path_tool->cur_path;
|
|
PathCurve * cur_curve;
|
|
PathSegment * cur_segment;
|
|
gint grab_pointer;
|
|
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("path_tool_button_press_canvas:\n");
|
|
#endif
|
|
|
|
grab_pointer = 1;
|
|
|
|
if (!cur_path) {
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("Fatal error: No current Path\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
gimp_draw_tool_pause (GIMP_DRAW_TOOL(path_tool));
|
|
|
|
if (path_tool->active_count == 1 && path_tool->single_active_segment != NULL
|
|
&& (path_tool->single_active_segment->prev == NULL || path_tool->single_active_segment->next == NULL)) {
|
|
cur_segment = path_tool->single_active_segment;
|
|
cur_curve = cur_segment->parent;
|
|
|
|
path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
|
|
|
|
if (cur_segment->next == NULL)
|
|
cur_curve->cur_segment = path_append_segment (cur_path, cur_curve, SEGMENT_BEZIER, path_tool->click_x, path_tool->click_y);
|
|
else
|
|
cur_curve->cur_segment = path_prepend_segment (cur_path, cur_curve, SEGMENT_BEZIER, path_tool->click_x, path_tool->click_y);
|
|
if (cur_curve->cur_segment) {
|
|
path_set_flags (path_tool, cur_path, cur_curve, cur_curve->cur_segment, SEGMENT_ACTIVE, 0);
|
|
}
|
|
} else {
|
|
if (path_tool->active_count == 0) {
|
|
path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
|
|
cur_path->cur_curve = path_add_curve (cur_path, path_tool->click_x, path_tool->click_y);
|
|
path_set_flags (path_tool, cur_path, cur_path->cur_curve, cur_path->cur_curve->segments, SEGMENT_ACTIVE, 0);
|
|
} else {
|
|
path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
|
|
}
|
|
}
|
|
|
|
gimp_draw_tool_resume (GIMP_DRAW_TOOL(path_tool));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static gint
|
|
gimp_path_tool_button_press_curve (GimpPathTool *path_tool,
|
|
guint32 time,
|
|
GimpDisplay *gdisp)
|
|
{
|
|
NPath * cur_path = path_tool->cur_path;
|
|
PathSegment * cur_segment;
|
|
gint grab_pointer;
|
|
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("path_tool_button_press_curve:\n");
|
|
#endif
|
|
|
|
grab_pointer = 1;
|
|
|
|
if (!cur_path) {
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("Fatal error: No current NPath\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
gimp_draw_tool_pause (GIMP_DRAW_TOOL(path_tool));
|
|
|
|
if (path_tool->click_modifier & GDK_SHIFT_MASK) {
|
|
cur_segment = path_curve_insert_anchor (path_tool->click_segment, path_tool->click_position);
|
|
path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
|
|
path_set_flags (path_tool, cur_path, path_tool->click_curve, cur_segment, SEGMENT_ACTIVE, 0);
|
|
path_tool->click_type = ON_ANCHOR;
|
|
path_tool->click_segment = cur_segment;
|
|
|
|
} else {
|
|
path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
|
|
path_set_flags (path_tool, cur_path, path_tool->click_curve, path_tool->click_segment, SEGMENT_ACTIVE, 0);
|
|
path_set_flags (path_tool, cur_path, path_tool->click_curve, path_tool->click_segment->next, SEGMENT_ACTIVE, 0);
|
|
}
|
|
gimp_draw_tool_resume (GIMP_DRAW_TOOL(path_tool));
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void
|
|
gimp_path_tool_button_release (GimpTool *tool,
|
|
GimpCoords *coords,
|
|
guint32 time,
|
|
GdkModifierType state,
|
|
GimpDisplay *gdisp)
|
|
{
|
|
GimpPathTool *path_tool;
|
|
|
|
path_tool = GIMP_PATH_TOOL (tool);
|
|
|
|
#ifdef PATH_TOOL_DEBUG
|
|
g_printerr ("path_tool_button_release\n");
|
|
#endif
|
|
|
|
path_tool->state &= ~PATH_TOOL_DRAG;
|
|
}
|
|
|
|
|
|
static void
|
|
gimp_path_tool_motion (GimpTool *tool,
|
|
GimpCoords *coords,
|
|
guint32 time,
|
|
GdkModifierType state,
|
|
GimpDisplay *gdisp)
|
|
{
|
|
GimpPathTool *path_tool;
|
|
|
|
path_tool = GIMP_PATH_TOOL (tool);
|
|
|
|
switch (path_tool->click_type)
|
|
{
|
|
case ON_ANCHOR:
|
|
gimp_path_tool_motion_anchor (path_tool, coords, state, gdisp);
|
|
break;
|
|
case ON_HANDLE:
|
|
gimp_path_tool_motion_handle (path_tool, coords, state, gdisp);
|
|
break;
|
|
case ON_CURVE:
|
|
gimp_path_tool_motion_curve (path_tool, coords, state, gdisp);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
gimp_path_tool_motion_anchor (GimpPathTool *path_tool,
|
|
GimpCoords *coords,
|
|
GdkModifierType state,
|
|
GimpDisplay *gdisp)
|
|
{
|
|
static gdouble dxsum = 0;
|
|
static gdouble dysum = 0;
|
|
|
|
gdouble dx, dy, d;
|
|
|
|
/* Dont do anything, if the user clicked with pressed CONTROL-Key,
|
|
* because he deleted an anchor.
|
|
*/
|
|
if (path_tool->click_modifier & GDK_CONTROL_MASK)
|
|
return;
|
|
|
|
if (! (path_tool->state & PATH_TOOL_DRAG))
|
|
{
|
|
path_tool->state |= PATH_TOOL_DRAG;
|
|
dxsum = 0;
|
|
dysum = 0;
|
|
}
|
|
|
|
dx = coords->x - path_tool->click_x - dxsum;
|
|
dy = coords->y - path_tool->click_y - dysum;
|
|
|
|
/* restrict to horizontal/vertical lines, if modifiers are pressed
|
|
* I'm not sure, if this is intuitive for the user. Esp. When moving
|
|
* an endpoint of an curve I'd expect, that the *line* is
|
|
* horiz/vertical - not the delta to the point, where the point was
|
|
* originally...
|
|
*/
|
|
if (state & GDK_MOD1_MASK)
|
|
{
|
|
if (state & GDK_CONTROL_MASK)
|
|
{
|
|
d = (fabs (dx) + fabs (dy)) / 2;
|
|
d = (fabs (coords->x - path_tool->click_x) +
|
|
fabs (coords->y - path_tool->click_y)) / 2;
|
|
dx = ((coords->x < path_tool->click_x) ? -d : d ) - dxsum;
|
|
dy = ((coords->y < path_tool->click_y) ? -d : d ) - dysum;
|
|
}
|
|
else
|
|
{
|
|
dx = - dxsum;
|
|
}
|
|
}
|
|
else if (state & GDK_CONTROL_MASK)
|
|
{
|
|
dy = - dysum;
|
|
}
|
|
|
|
path_tool->draw |= PATH_TOOL_REDRAW_ACTIVE;
|
|
|
|
gimp_draw_tool_pause (GIMP_DRAW_TOOL (path_tool));
|
|
|
|
path_offset_active (path_tool->cur_path, dx, dy);
|
|
|
|
dxsum += dx;
|
|
dysum += dy;
|
|
|
|
gimp_draw_tool_resume (GIMP_DRAW_TOOL (path_tool));
|
|
|
|
path_tool->draw &= ~PATH_TOOL_REDRAW_ACTIVE;
|
|
}
|
|
|
|
static void
|
|
gimp_path_tool_motion_handle (GimpPathTool *path_tool,
|
|
GimpCoords *coords,
|
|
GdkModifierType state,
|
|
GimpDisplay *gdisp)
|
|
{
|
|
static gdouble dxsum = 0;
|
|
static gdouble dysum = 0;
|
|
|
|
gdouble dx, dy;
|
|
|
|
/* Dont do anything, if the user clicked with pressed CONTROL-Key,
|
|
* because he moved the handle to the anchor an anchor.
|
|
* XXX: Not yet! :-)
|
|
*/
|
|
if (path_tool->click_modifier & GDK_CONTROL_MASK)
|
|
return;
|
|
|
|
if (! (path_tool->state & PATH_TOOL_DRAG))
|
|
{
|
|
path_tool->state |= PATH_TOOL_DRAG;
|
|
dxsum = 0;
|
|
dysum = 0;
|
|
}
|
|
|
|
dx = coords->x - path_tool->click_x - dxsum;
|
|
dy = coords->y - path_tool->click_y - dysum;
|
|
|
|
path_tool->draw |= PATH_TOOL_REDRAW_ACTIVE;
|
|
|
|
gimp_draw_tool_pause (GIMP_DRAW_TOOL (path_tool));
|
|
|
|
path_curve_drag_handle (path_tool->click_segment,
|
|
dx, dy,
|
|
path_tool->click_handle_id);
|
|
|
|
dxsum += dx;
|
|
dysum += dy;
|
|
|
|
gimp_draw_tool_resume (GIMP_DRAW_TOOL (path_tool));
|
|
|
|
path_tool->draw &= ~PATH_TOOL_REDRAW_ACTIVE;
|
|
}
|
|
|
|
static void
|
|
gimp_path_tool_motion_curve (GimpPathTool *path_tool,
|
|
GimpCoords *coords,
|
|
GdkModifierType state,
|
|
GimpDisplay *gdisp)
|
|
{
|
|
static gdouble dxsum = 0;
|
|
static gdouble dysum = 0;
|
|
|
|
gdouble dx, dy;
|
|
|
|
if (! (path_tool->state & PATH_TOOL_DRAG))
|
|
{
|
|
path_tool->state |= PATH_TOOL_DRAG;
|
|
dxsum = 0;
|
|
dysum = 0;
|
|
}
|
|
|
|
dx = coords->x - path_tool->click_x - dxsum;
|
|
dy = coords->y - path_tool->click_y - dysum;
|
|
|
|
path_tool->draw |= PATH_TOOL_REDRAW_ACTIVE;
|
|
|
|
gimp_draw_tool_pause (GIMP_DRAW_TOOL (path_tool));
|
|
|
|
path_curve_drag_segment (path_tool->click_segment,
|
|
path_tool->click_position,
|
|
dx, dy);
|
|
|
|
dxsum += dx;
|
|
dysum += dy;
|
|
|
|
gimp_draw_tool_resume (GIMP_DRAW_TOOL (path_tool));
|
|
|
|
path_tool->draw &= ~PATH_TOOL_REDRAW_ACTIVE;
|
|
}
|
|
|
|
static void
|
|
gimp_path_tool_cursor_update (GimpTool *tool,
|
|
GimpCoords *coords,
|
|
GdkModifierType state,
|
|
GimpDisplay *gdisp)
|
|
{
|
|
GimpCursorModifier cmodifier = GIMP_CURSOR_MODIFIER_NONE;
|
|
gint cursor_location;
|
|
|
|
cursor_location = path_tool_cursor_position (GIMP_PATH_TOOL (tool)->cur_path,
|
|
coords->x,
|
|
coords->y,
|
|
PATH_TOOL_HALFWIDTH,
|
|
PATH_TOOL_HALFWIDTH,
|
|
NULL, NULL, NULL, NULL, NULL);
|
|
|
|
/* FIXME: add GIMP_PATH_TOOL_CURSOR */
|
|
|
|
switch (cursor_location)
|
|
{
|
|
case ON_CANVAS:
|
|
cmodifier = GIMP_CURSOR_MODIFIER_PLUS;
|
|
break;
|
|
case ON_ANCHOR:
|
|
cmodifier = GIMP_CURSOR_MODIFIER_MOVE;
|
|
break;
|
|
case ON_HANDLE:
|
|
cmodifier = GIMP_CURSOR_MODIFIER_MOVE;
|
|
break;
|
|
case ON_CURVE:
|
|
cmodifier = GIMP_CURSOR_MODIFIER_NONE;
|
|
break;
|
|
default:
|
|
g_warning ("gimp_path_tool_cursor_update(): bad cursor_location");
|
|
break;
|
|
}
|
|
|
|
gimp_tool_control_set_cursor_modifier (tool->control, cmodifier);
|
|
|
|
GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, gdisp);
|
|
}
|
|
|
|
|
|
/* This is a CurveTraverseFunc */
|
|
static void
|
|
gimp_path_tool_draw_helper (NPath *path,
|
|
PathCurve *curve,
|
|
PathSegment *segment,
|
|
gpointer tool)
|
|
{
|
|
GimpPathTool *path_tool;
|
|
GimpDrawTool *draw_tool;
|
|
gboolean draw = TRUE;
|
|
|
|
path_tool = GIMP_PATH_TOOL (tool);
|
|
draw_tool = GIMP_DRAW_TOOL (tool);
|
|
|
|
if (path_tool->draw & PATH_TOOL_REDRAW_ACTIVE)
|
|
draw = (segment->flags & SEGMENT_ACTIVE ||
|
|
(segment->next && segment->next->flags & SEGMENT_ACTIVE));
|
|
|
|
if (segment->flags & SEGMENT_ACTIVE)
|
|
{
|
|
gimp_draw_tool_draw_handle (draw_tool,
|
|
GIMP_HANDLE_CIRCLE,
|
|
segment->x, segment->y,
|
|
PATH_TOOL_WIDTH,
|
|
PATH_TOOL_WIDTH,
|
|
GTK_ANCHOR_CENTER,
|
|
FALSE);
|
|
}
|
|
else
|
|
{
|
|
gimp_draw_tool_draw_handle (draw_tool,
|
|
GIMP_HANDLE_FILLED_CIRCLE,
|
|
segment->x, segment->y,
|
|
PATH_TOOL_WIDTH,
|
|
PATH_TOOL_WIDTH,
|
|
GTK_ANCHOR_CENTER,
|
|
FALSE);
|
|
}
|
|
|
|
if (segment->next)
|
|
path_curve_draw_segment (draw_tool, segment);
|
|
}
|
|
|
|
static void
|
|
gimp_path_tool_draw (GimpDrawTool *draw_tool)
|
|
{
|
|
GimpPathTool *path_tool;
|
|
|
|
path_tool = GIMP_PATH_TOOL (draw_tool);
|
|
|
|
path_traverse_path (path_tool->click_path, NULL, gimp_path_tool_draw_helper, NULL, draw_tool);
|
|
}
|
|
|