Commit 150bea1e authored by Michael Natterer's avatar Michael Natterer 😴 Committed by Michael Natterer

Implemented "Snap to Canvas Edges" (fixes bug #152971) and "Snap to Active

2005-01-03  Michael Natterer  <mitch@gimp.org>

	Implemented "Snap to Canvas Edges" (fixes bug #152971) and
	"Snap to Active Path" (half way done):

	* app/core/gimpimage-snap.[ch]: added boolean snap_to_canvas and
	snap_to_vectors parameters (snap_to_vectors works fine when
	snapping to a point, but is unimplemented for snapping to a
	rectangle).

	* app/display/gimpdisplayshell.[ch] (struct GimpDisplayShell):
	added snap_to_canvas and snap_to_vectors booleans.

	* app/display/gimpdisplayshell-appearance.[ch]: added API to
	get/set them.

	* app/actions/view-actions.c
	* app/actions/view-commands.[ch]
	* app/widgets/gimphelp-ids.h: added actions, callbacks and help IDs.

	* menus/image-menu.xml.in: added them to Image->View.
parent 28251be0
2005-01-03 Michael Natterer <mitch@gimp.org>
Implemented "Snap to Canvas Edges" (fixes bug #152971) and
"Snap to Active Path" (half way done):
* app/core/gimpimage-snap.[ch]: added boolean snap_to_canvas and
snap_to_vectors parameters (snap_to_vectors works fine when
snapping to a point, but is unimplemented for snapping to a
rectangle).
* app/display/gimpdisplayshell.[ch] (struct GimpDisplayShell):
added snap_to_canvas and snap_to_vectors booleans.
* app/display/gimpdisplayshell-appearance.[ch]: added API to
get/set them.
* app/actions/view-actions.c
* app/actions/view-commands.[ch]
* app/widgets/gimphelp-ids.h: added actions, callbacks and help IDs.
* menus/image-menu.xml.in: added them to Image->View.
2005-01-03 Sven Neumann <neumann@jpk.com> 2005-01-03 Sven Neumann <neumann@jpk.com>
* plug-ins/ifscompose/ifscompose.c: use g_free() to release memory * plug-ins/ifscompose/ifscompose.c: use g_free() to release memory
......
...@@ -157,6 +157,18 @@ static GimpToggleActionEntry view_toggle_actions[] = ...@@ -157,6 +157,18 @@ static GimpToggleActionEntry view_toggle_actions[] =
FALSE, FALSE,
GIMP_HELP_VIEW_SNAP_TO_GRID }, GIMP_HELP_VIEW_SNAP_TO_GRID },
{ "view-snap-to-canvas", NULL,
N_("S_nap to Canvas Edges"), NULL, NULL,
G_CALLBACK (view_snap_to_canvas_cmd_callback),
FALSE,
GIMP_HELP_VIEW_SNAP_TO_CANVAS },
{ "view-snap-to-vectors", NULL,
N_("Snap to Active Pat_h"), NULL, NULL,
G_CALLBACK (view_snap_to_vectors_cmd_callback),
FALSE,
GIMP_HELP_VIEW_SNAP_TO_VECTORS },
{ "view-show-menubar", NULL, { "view-show-menubar", NULL,
N_("Show _Menubar"), NULL, NULL, N_("Show _Menubar"), NULL, NULL,
G_CALLBACK (view_toggle_menubar_cmd_callback), G_CALLBACK (view_toggle_menubar_cmd_callback),
...@@ -514,6 +526,8 @@ view_actions_update (GimpActionGroup *group, ...@@ -514,6 +526,8 @@ view_actions_update (GimpActionGroup *group,
SET_ACTIVE ("view-snap-to-guides", gdisp && shell->snap_to_guides); SET_ACTIVE ("view-snap-to-guides", gdisp && shell->snap_to_guides);
SET_ACTIVE ("view-show-grid", gdisp && options->show_grid); SET_ACTIVE ("view-show-grid", gdisp && options->show_grid);
SET_ACTIVE ("view-snap-to-grid", gdisp && shell->snap_to_grid); SET_ACTIVE ("view-snap-to-grid", gdisp && shell->snap_to_grid);
SET_ACTIVE ("view-snap-to-canvas", gdisp && shell->snap_to_canvas);
SET_ACTIVE ("view-snap-to-vectors", gdisp && shell->snap_to_vectors);
if (gdisp) if (gdisp)
{ {
......
...@@ -526,6 +526,38 @@ view_snap_to_grid_cmd_callback (GtkAction *action, ...@@ -526,6 +526,38 @@ view_snap_to_grid_cmd_callback (GtkAction *action,
gimp_display_shell_set_snap_to_grid (shell, active); gimp_display_shell_set_snap_to_grid (shell, active);
} }
void
view_snap_to_canvas_cmd_callback (GtkAction *action,
gpointer data)
{
GimpDisplay *gdisp;
GimpDisplayShell *shell;
gboolean active;
return_if_no_display (gdisp, data);
shell = GIMP_DISPLAY_SHELL (gdisp->shell);
active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
gimp_display_shell_set_snap_to_canvas (shell, active);
}
void
view_snap_to_vectors_cmd_callback (GtkAction *action,
gpointer data)
{
GimpDisplay *gdisp;
GimpDisplayShell *shell;
gboolean active;
return_if_no_display (gdisp, data);
shell = GIMP_DISPLAY_SHELL (gdisp->shell);
active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
gimp_display_shell_set_snap_to_vectors (shell, active);
}
void void
view_padding_color_cmd_callback (GtkAction *action, view_padding_color_cmd_callback (GtkAction *action,
gint value, gint value,
......
...@@ -73,6 +73,10 @@ void view_toggle_grid_cmd_callback (GtkAction *action, ...@@ -73,6 +73,10 @@ void view_toggle_grid_cmd_callback (GtkAction *action,
gpointer data); gpointer data);
void view_snap_to_grid_cmd_callback (GtkAction *action, void view_snap_to_grid_cmd_callback (GtkAction *action,
gpointer data); gpointer data);
void view_snap_to_canvas_cmd_callback (GtkAction *action,
gpointer data);
void view_snap_to_vectors_cmd_callback (GtkAction *action,
gpointer data);
void view_padding_color_cmd_callback (GtkAction *action, void view_padding_color_cmd_callback (GtkAction *action,
gint value, gint value,
gpointer data); gpointer data);
......
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
#include "gimpimage-guides.h" #include "gimpimage-guides.h"
#include "gimpimage-snap.h" #include "gimpimage-snap.h"
#include "vectors/gimpstroke.h"
#include "vectors/gimpvectors.h"
#include "gimp-intl.h" #include "gimp-intl.h"
...@@ -40,7 +43,8 @@ gimp_image_snap_x (GimpImage *gimage, ...@@ -40,7 +43,8 @@ gimp_image_snap_x (GimpImage *gimage,
gdouble *tx, gdouble *tx,
gdouble epsilon_x, gdouble epsilon_x,
gboolean snap_to_guides, gboolean snap_to_guides,
gboolean snap_to_grid) gboolean snap_to_grid,
gboolean snap_to_canvas)
{ {
GList *list; GList *list;
GimpGuide *guide; GimpGuide *guide;
...@@ -55,7 +59,7 @@ gimp_image_snap_x (GimpImage *gimage, ...@@ -55,7 +59,7 @@ gimp_image_snap_x (GimpImage *gimage,
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
g_return_val_if_fail (tx != NULL, FALSE); g_return_val_if_fail (tx != NULL, FALSE);
if (! snap_to_guides && ! snap_to_grid) if (! (snap_to_guides || snap_to_grid || snap_to_canvas))
return FALSE; return FALSE;
*tx = x; *tx = x;
...@@ -111,6 +115,27 @@ gimp_image_snap_x (GimpImage *gimage, ...@@ -111,6 +115,27 @@ gimp_image_snap_x (GimpImage *gimage,
} }
} }
if (snap_to_canvas)
{
dist = ABS (x);
if (dist < MIN (epsilon_x, mindist))
{
mindist = dist;
*tx = 0;
snapped = TRUE;
}
dist = ABS (gimage->width - x);
if (dist < MIN (epsilon_x, mindist))
{
mindist = dist;
*tx = gimage->width;
snapped = TRUE;
}
}
return snapped; return snapped;
} }
...@@ -120,7 +145,8 @@ gimp_image_snap_y (GimpImage *gimage, ...@@ -120,7 +145,8 @@ gimp_image_snap_y (GimpImage *gimage,
gdouble *ty, gdouble *ty,
gdouble epsilon_y, gdouble epsilon_y,
gboolean snap_to_guides, gboolean snap_to_guides,
gboolean snap_to_grid) gboolean snap_to_grid,
gboolean snap_to_canvas)
{ {
GList *list; GList *list;
GimpGuide *guide; GimpGuide *guide;
...@@ -135,7 +161,7 @@ gimp_image_snap_y (GimpImage *gimage, ...@@ -135,7 +161,7 @@ gimp_image_snap_y (GimpImage *gimage,
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
g_return_val_if_fail (ty != NULL, FALSE); g_return_val_if_fail (ty != NULL, FALSE);
if (! snap_to_guides && ! snap_to_grid) if (! (snap_to_guides || snap_to_grid || snap_to_canvas))
return FALSE; return FALSE;
*ty = y; *ty = y;
...@@ -191,6 +217,27 @@ gimp_image_snap_y (GimpImage *gimage, ...@@ -191,6 +217,27 @@ gimp_image_snap_y (GimpImage *gimage,
} }
} }
if (snap_to_canvas)
{
dist = ABS (y);
if (dist < MIN (epsilon_y, mindist))
{
mindist = dist;
*ty = 0;
snapped = TRUE;
}
dist = ABS (gimage->height - y);
if (dist < MIN (epsilon_y, mindist))
{
mindist = dist;
*ty = gimage->height;
snapped = TRUE;
}
}
return snapped; return snapped;
} }
...@@ -203,7 +250,9 @@ gimp_image_snap_point (GimpImage *gimage, ...@@ -203,7 +250,9 @@ gimp_image_snap_point (GimpImage *gimage,
gdouble epsilon_x, gdouble epsilon_x,
gdouble epsilon_y, gdouble epsilon_y,
gboolean snap_to_guides, gboolean snap_to_guides,
gboolean snap_to_grid) gboolean snap_to_grid,
gboolean snap_to_canvas,
gboolean snap_to_vectors)
{ {
GList *list; GList *list;
GimpGuide *guide; GimpGuide *guide;
...@@ -219,7 +268,7 @@ gimp_image_snap_point (GimpImage *gimage, ...@@ -219,7 +268,7 @@ gimp_image_snap_point (GimpImage *gimage,
g_return_val_if_fail (tx != NULL, FALSE); g_return_val_if_fail (tx != NULL, FALSE);
g_return_val_if_fail (ty != NULL, FALSE); g_return_val_if_fail (ty != NULL, FALSE);
if (! snap_to_guides && ! snap_to_grid) if (! (snap_to_guides || snap_to_grid || snap_to_canvas || snap_to_vectors))
return FALSE; return FALSE;
*tx = x; *tx = x;
...@@ -315,6 +364,80 @@ gimp_image_snap_point (GimpImage *gimage, ...@@ -315,6 +364,80 @@ gimp_image_snap_point (GimpImage *gimage,
} }
} }
if (snap_to_canvas)
{
dist = ABS (x);
if (dist < MIN (epsilon_x, minxdist))
{
minxdist = dist;
*tx = 0;
snapped = TRUE;
}
dist = ABS (gimage->width - x);
if (dist < MIN (epsilon_x, minxdist))
{
minxdist = dist;
*tx = gimage->width;
snapped = TRUE;
}
dist = ABS (y);
if (dist < MIN (epsilon_y, minydist))
{
minydist = dist;
*ty = 0;
snapped = TRUE;
}
dist = ABS (gimage->height - y);
if (dist < MIN (epsilon_y, minydist))
{
minydist = dist;
*ty = gimage->height;
snapped = TRUE;
}
}
if (snap_to_vectors && gimage->active_vectors != NULL)
{
GimpVectors *vectors = gimp_image_get_active_vectors (gimage);
GimpStroke *stroke = NULL;
GimpCoords coords = { x, y, 0, 0, 0 };
while ((stroke = gimp_vectors_stroke_get_next (vectors, stroke)))
{
GimpCoords nearest;
if (gimp_stroke_nearest_point_get (stroke, &coords, 1.0,
&nearest,
NULL, NULL, NULL) >= 0)
{
dist = ABS (nearest.x - x);
if (dist < MIN (epsilon_x, minxdist))
{
minxdist = dist;
*tx = nearest.x;
snapped = TRUE;
}
dist = ABS (nearest.y - y);
if (dist < MIN (epsilon_y, minydist))
{
minydist = dist;
*ty = nearest.y;
snapped = TRUE;
}
}
}
}
return snapped; return snapped;
} }
...@@ -329,7 +452,9 @@ gimp_image_snap_rectangle (GimpImage *gimage, ...@@ -329,7 +452,9 @@ gimp_image_snap_rectangle (GimpImage *gimage,
gdouble epsilon_x, gdouble epsilon_x,
gdouble epsilon_y, gdouble epsilon_y,
gboolean snap_to_guides, gboolean snap_to_guides,
gboolean snap_to_grid) gboolean snap_to_grid,
gboolean snap_to_canvas,
gboolean snap_to_vectors)
{ {
gdouble nx1, ny1; gdouble nx1, ny1;
gdouble nx2, ny2; gdouble nx2, ny2;
...@@ -339,28 +464,36 @@ gimp_image_snap_rectangle (GimpImage *gimage, ...@@ -339,28 +464,36 @@ gimp_image_snap_rectangle (GimpImage *gimage,
g_return_val_if_fail (tx1 != NULL, FALSE); g_return_val_if_fail (tx1 != NULL, FALSE);
g_return_val_if_fail (ty1 != NULL, FALSE); g_return_val_if_fail (ty1 != NULL, FALSE);
if (! snap_to_guides && ! snap_to_grid) if (! (snap_to_guides || snap_to_grid || snap_to_canvas || snap_to_vectors))
return FALSE; return FALSE;
#ifdef __GNUC__
#warning FIXME: implement rectangle snapping to vectors
#endif
*tx1 = x1; *tx1 = x1;
*ty1 = y1; *ty1 = y1;
snap1 = gimp_image_snap_x (gimage, x1, &nx1, snap1 = gimp_image_snap_x (gimage, x1, &nx1,
epsilon_x, epsilon_x,
snap_to_guides, snap_to_guides,
snap_to_grid); snap_to_grid,
snap_to_canvas);
snap2 = gimp_image_snap_x (gimage, x2, &nx2, snap2 = gimp_image_snap_x (gimage, x2, &nx2,
epsilon_x, epsilon_x,
snap_to_guides, snap_to_guides,
snap_to_grid); snap_to_grid,
snap_to_canvas);
snap3 = gimp_image_snap_y (gimage, y1, &ny1, snap3 = gimp_image_snap_y (gimage, y1, &ny1,
epsilon_y, epsilon_y,
snap_to_guides, snap_to_guides,
snap_to_grid); snap_to_grid,
snap_to_canvas);
snap4 = gimp_image_snap_y (gimage, y2, &ny2, snap4 = gimp_image_snap_y (gimage, y2, &ny2,
epsilon_y, epsilon_y,
snap_to_guides, snap_to_guides,
snap_to_grid); snap_to_grid,
snap_to_canvas);
if (snap1 && snap2) if (snap1 && snap2)
{ {
......
...@@ -25,13 +25,15 @@ gboolean gimp_image_snap_x (GimpImage *gimage, ...@@ -25,13 +25,15 @@ gboolean gimp_image_snap_x (GimpImage *gimage,
gdouble *tx, gdouble *tx,
gdouble epsilon_x, gdouble epsilon_x,
gboolean snap_to_guides, gboolean snap_to_guides,
gboolean snap_to_grid); gboolean snap_to_grid,
gboolean snap_to_canvas);
gboolean gimp_image_snap_y (GimpImage *gimage, gboolean gimp_image_snap_y (GimpImage *gimage,
gdouble y, gdouble y,
gdouble *ty, gdouble *ty,
gdouble epsilon_y, gdouble epsilon_y,
gboolean snap_to_guides, gboolean snap_to_guides,
gboolean snap_to_grid); gboolean snap_to_grid,
gboolean snap_to_canvas);
gboolean gimp_image_snap_point (GimpImage *gimage, gboolean gimp_image_snap_point (GimpImage *gimage,
gdouble x, gdouble x,
gdouble y, gdouble y,
...@@ -40,7 +42,9 @@ gboolean gimp_image_snap_point (GimpImage *gimage, ...@@ -40,7 +42,9 @@ gboolean gimp_image_snap_point (GimpImage *gimage,
gdouble epsilon_x, gdouble epsilon_x,
gdouble epsilon_y, gdouble epsilon_y,
gboolean snap_to_guides, gboolean snap_to_guides,
gboolean snap_to_grid); gboolean snap_to_grid,
gboolean snap_to_canvas,
gboolean snap_to_vectors);
gboolean gimp_image_snap_rectangle (GimpImage *gimage, gboolean gimp_image_snap_rectangle (GimpImage *gimage,
gdouble x1, gdouble x1,
gdouble y1, gdouble y1,
...@@ -51,7 +55,9 @@ gboolean gimp_image_snap_rectangle (GimpImage *gimage, ...@@ -51,7 +55,9 @@ gboolean gimp_image_snap_rectangle (GimpImage *gimage,
gdouble epsilon_x, gdouble epsilon_x,
gdouble epsilon_y, gdouble epsilon_y,
gboolean snap_to_guides, gboolean snap_to_guides,
gboolean snap_to_grid); gboolean snap_to_grid,
gboolean snap_to_canvas,
gboolean snap_to_vectors);
#endif /* __GIMP_IMAGE_SNAP_H__ */ #endif /* __GIMP_IMAGE_SNAP_H__ */
...@@ -452,6 +452,56 @@ gimp_display_shell_get_snap_to_guides (GimpDisplayShell *shell) ...@@ -452,6 +452,56 @@ gimp_display_shell_get_snap_to_guides (GimpDisplayShell *shell)
return shell->snap_to_guides; return shell->snap_to_guides;
} }
void
gimp_display_shell_set_snap_to_canvas (GimpDisplayShell *shell,
gboolean snap)
{
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
if (snap != shell->snap_to_canvas)
{
shell->snap_to_canvas = snap ? TRUE : FALSE;
SET_ACTIVE (shell->menubar_manager, "view-snap-to-canvas", snap);
if (IS_ACTIVE_DISPLAY (shell))
SET_ACTIVE (shell->popup_manager, "view-snap-to-canvas", snap);
}
}
gboolean
gimp_display_shell_get_snap_to_canvas (GimpDisplayShell *shell)
{
g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE);
return shell->snap_to_canvas;
}
void
gimp_display_shell_set_snap_to_vectors (GimpDisplayShell *shell,
gboolean snap)
{
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
if (snap != shell->snap_to_vectors)
{
shell->snap_to_vectors = snap ? TRUE : FALSE;
SET_ACTIVE (shell->menubar_manager, "view-snap-to-vectors", snap);
if (IS_ACTIVE_DISPLAY (shell))
SET_ACTIVE (shell->popup_manager, "view-snap-to-vectors", snap);
}
}
gboolean
gimp_display_shell_get_snap_to_vectors (GimpDisplayShell *shell)
{
g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE);
return shell->snap_to_vectors;
}
void void
gimp_display_shell_set_padding (GimpDisplayShell *shell, gimp_display_shell_set_padding (GimpDisplayShell *shell,
GimpCanvasPaddingMode padding_mode, GimpCanvasPaddingMode padding_mode,
......
...@@ -68,6 +68,14 @@ void gimp_display_shell_set_snap_to_guides (GimpDisplayShell *shell, ...@@ -68,6 +68,14 @@ void gimp_display_shell_set_snap_to_guides (GimpDisplayShell *shell,
gboolean snap); gboolean snap);
gboolean gimp_display_shell_get_snap_to_guides (GimpDisplayShell *shell); gboolean gimp_display_shell_get_snap_to_guides (GimpDisplayShell *shell);
void gimp_display_shell_set_snap_to_canvas (GimpDisplayShell *shell,
gboolean snap);
gboolean gimp_display_shell_get_snap_to_canvas (GimpDisplayShell *shell);
void gimp_display_shell_set_snap_to_vectors (GimpDisplayShell *shell,
gboolean snap);
gboolean gimp_display_shell_get_snap_to_vectors (GimpDisplayShell *shell);
void gimp_display_shell_set_padding (GimpDisplayShell *shell, void gimp_display_shell_set_padding (GimpDisplayShell *shell,
GimpCanvasPaddingMode mode, GimpCanvasPaddingMode mode,
const GimpRGB *color); const GimpRGB *color);
......
...@@ -249,6 +249,8 @@ gimp_display_shell_init (GimpDisplayShell *shell) ...@@ -249,6 +249,8 @@ gimp_display_shell_init (GimpDisplayShell *shell)
shell->proximity = FALSE; shell->proximity = FALSE;
shell->snap_to_guides = TRUE; shell->snap_to_guides = TRUE;
shell->snap_to_grid = FALSE; shell->snap_to_grid = FALSE;
shell->snap_to_canvas = FALSE;
shell->snap_to_vectors = FALSE;
shell->select = NULL; shell->select = NULL;
...@@ -1105,9 +1107,11 @@ gimp_display_shell_snap_coords (GimpDisplayShell *shell, ...@@ -1105,9 +1107,11 @@ gimp_display_shell_snap_coords (GimpDisplayShell *shell,
gint snap_width, gint snap_width,
gint snap_height) gint snap_height)
{ {
gboolean snap_to_guides = FALSE; gboolean snap_to_guides = FALSE;
gboolean snap_to_grid = FALSE; gboolean snap_to_grid = FALSE;
gboolean snapped = FALSE; gboolean snap_to_canvas = FALSE;
gboolean snap_to_vectors = FALSE;
gboolean snapped = FALSE;
g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE); g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE);
g_return_val_if_fail (coords != NULL, FALSE); g_return_val_if_fail (coords != NULL, FALSE);
...@@ -1115,7 +1119,7 @@ gimp_display_shell_snap_coords (GimpDisplayShell *shell, ...@@ -1115,7 +1119,7 @@ gimp_display_shell_snap_coords (GimpDisplayShell *shell,