2006-12-10 05:33:38 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
1997-11-25 06:05:25 +08:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
1997-11-25 06:05:25 +08:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-18 06:28:01 +08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
1997-11-25 06:05:25 +08:00
|
|
|
* (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
|
2018-07-12 05:27:07 +08:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
1997-11-25 06:05:25 +08:00
|
|
|
*/
|
2000-12-17 05:37:03 +08:00
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2008-10-10 04:24:04 +08:00
|
|
|
#include <gegl.h>
|
2000-12-29 23:22:01 +08:00
|
|
|
#include <gtk/gtk.h>
|
2000-12-17 05:37:03 +08:00
|
|
|
|
2001-09-26 07:23:09 +08:00
|
|
|
#include "display-types.h"
|
2000-12-17 05:37:03 +08:00
|
|
|
|
2002-11-19 04:50:31 +08:00
|
|
|
#include "config/gimpdisplayconfig.h"
|
|
|
|
|
|
|
|
#include "core/gimp.h"
|
2012-04-10 18:09:37 +08:00
|
|
|
#include "core/gimp-cairo.h"
|
2012-03-19 21:22:41 +08:00
|
|
|
#include "core/gimpboundary.h"
|
2010-10-03 06:28:40 +08:00
|
|
|
#include "core/gimpchannel.h"
|
2001-05-09 10:32:03 +08:00
|
|
|
#include "core/gimpimage.h"
|
|
|
|
|
2001-09-26 07:23:09 +08:00
|
|
|
#include "gimpdisplay.h"
|
2001-11-01 05:20:09 +08:00
|
|
|
#include "gimpdisplayshell.h"
|
2003-03-20 19:31:33 +08:00
|
|
|
#include "gimpdisplayshell-appearance.h"
|
2010-08-25 00:07:31 +08:00
|
|
|
#include "gimpdisplayshell-draw.h"
|
2009-10-03 05:55:26 +08:00
|
|
|
#include "gimpdisplayshell-expose.h"
|
2001-11-11 07:03:22 +08:00
|
|
|
#include "gimpdisplayshell-selection.h"
|
2003-01-04 02:01:30 +08:00
|
|
|
#include "gimpdisplayshell-transform.h"
|
2001-09-26 07:23:09 +08:00
|
|
|
|
2000-12-29 23:22:01 +08:00
|
|
|
|
2006-09-05 00:13:28 +08:00
|
|
|
struct _Selection
|
|
|
|
{
|
|
|
|
GimpDisplayShell *shell; /* shell that owns the selection */
|
2010-08-24 23:36:42 +08:00
|
|
|
|
2018-07-14 01:09:01 +08:00
|
|
|
GimpSegment *segs_in; /* segments of area boundary */
|
2010-08-25 07:58:00 +08:00
|
|
|
gint n_segs_in; /* number of segments in segs_in */
|
2010-08-24 23:36:42 +08:00
|
|
|
|
2018-07-14 01:09:01 +08:00
|
|
|
GimpSegment *segs_out; /* segments of area boundary */
|
2010-08-25 07:58:00 +08:00
|
|
|
gint n_segs_out; /* number of segments in segs_out */
|
2010-08-24 23:36:42 +08:00
|
|
|
|
2006-09-05 00:13:28 +08:00
|
|
|
guint index; /* index of current stipple pattern */
|
|
|
|
gint paused; /* count of pause requests */
|
2010-10-09 18:51:20 +08:00
|
|
|
gboolean shell_visible; /* visility of the display shell */
|
2010-10-09 18:55:11 +08:00
|
|
|
gboolean show_selection; /* is the selection visible? */
|
2006-09-05 04:56:14 +08:00
|
|
|
guint timeout; /* timer for successive draws */
|
2010-08-27 02:52:52 +08:00
|
|
|
cairo_pattern_t *segs_in_mask; /* cache for rendered segments */
|
2006-09-05 00:13:28 +08:00
|
|
|
};
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
|
2001-06-18 21:10:03 +08:00
|
|
|
/* local function prototypes */
|
|
|
|
|
2012-03-19 22:04:20 +08:00
|
|
|
static void selection_start (Selection *selection);
|
|
|
|
static void selection_stop (Selection *selection);
|
2006-09-05 01:18:38 +08:00
|
|
|
|
2018-07-03 22:01:02 +08:00
|
|
|
static void selection_draw (Selection *selection,
|
|
|
|
cairo_t *cr);
|
2012-03-19 22:04:20 +08:00
|
|
|
static void selection_undraw (Selection *selection);
|
2006-09-05 01:18:38 +08:00
|
|
|
|
2012-03-19 22:04:20 +08:00
|
|
|
static void selection_render_mask (Selection *selection);
|
2006-09-05 02:22:50 +08:00
|
|
|
|
2013-04-25 06:29:58 +08:00
|
|
|
static void selection_zoom_segs (Selection *selection,
|
2012-03-19 22:04:20 +08:00
|
|
|
const GimpBoundSeg *src_segs,
|
|
|
|
GimpSegment *dest_segs,
|
|
|
|
gint n_segs);
|
|
|
|
static void selection_generate_segs (Selection *selection);
|
|
|
|
static void selection_free_segs (Selection *selection);
|
2006-09-05 02:22:50 +08:00
|
|
|
|
2012-03-19 22:04:20 +08:00
|
|
|
static gboolean selection_start_timeout (Selection *selection);
|
|
|
|
static gboolean selection_timeout (Selection *selection);
|
2006-09-05 04:56:14 +08:00
|
|
|
|
2006-09-05 05:23:50 +08:00
|
|
|
static gboolean selection_window_state_event (GtkWidget *shell,
|
|
|
|
GdkEventWindowState *event,
|
|
|
|
Selection *selection);
|
|
|
|
static gboolean selection_visibility_notify_event (GtkWidget *shell,
|
|
|
|
GdkEventVisibility *event,
|
|
|
|
Selection *selection);
|
2003-11-11 20:43:52 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2001-06-18 21:10:03 +08:00
|
|
|
/* public functions */
|
|
|
|
|
2006-09-05 01:18:38 +08:00
|
|
|
void
|
|
|
|
gimp_display_shell_selection_init (GimpDisplayShell *shell)
|
2001-06-18 21:10:03 +08:00
|
|
|
{
|
2006-09-05 04:56:14 +08:00
|
|
|
Selection *selection;
|
2001-06-18 21:10:03 +08:00
|
|
|
|
2006-09-05 01:18:38 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
|
|
|
g_return_if_fail (shell->selection == NULL);
|
2001-11-11 07:03:22 +08:00
|
|
|
|
2007-05-23 17:04:20 +08:00
|
|
|
selection = g_slice_new0 (Selection);
|
2001-06-18 21:10:03 +08:00
|
|
|
|
2010-10-09 18:55:11 +08:00
|
|
|
selection->shell = shell;
|
|
|
|
selection->shell_visible = TRUE;
|
|
|
|
selection->show_selection = gimp_display_shell_get_show_selection (shell);
|
2001-06-18 21:10:03 +08:00
|
|
|
|
2006-09-05 04:56:14 +08:00
|
|
|
shell->selection = selection;
|
2001-06-18 21:10:03 +08:00
|
|
|
|
2006-09-05 05:23:50 +08:00
|
|
|
g_signal_connect (shell, "window-state-event",
|
|
|
|
G_CALLBACK (selection_window_state_event),
|
|
|
|
selection);
|
2006-09-05 05:11:14 +08:00
|
|
|
g_signal_connect (shell, "visibility-notify-event",
|
|
|
|
G_CALLBACK (selection_visibility_notify_event),
|
2006-09-05 04:56:14 +08:00
|
|
|
selection);
|
2001-06-18 21:10:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-09-05 01:18:38 +08:00
|
|
|
gimp_display_shell_selection_free (GimpDisplayShell *shell)
|
2001-06-18 21:10:03 +08:00
|
|
|
{
|
2013-06-21 20:37:56 +08:00
|
|
|
Selection *selection;
|
|
|
|
|
2006-09-05 01:18:38 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
2013-06-17 02:14:35 +08:00
|
|
|
g_return_if_fail (shell->selection != NULL);
|
2001-06-18 21:10:03 +08:00
|
|
|
|
2013-06-21 20:37:56 +08:00
|
|
|
selection = shell->selection;
|
2006-09-05 04:56:14 +08:00
|
|
|
|
2013-06-17 02:14:35 +08:00
|
|
|
selection_stop (selection);
|
2006-09-05 04:56:14 +08:00
|
|
|
|
2013-06-17 02:14:35 +08:00
|
|
|
g_signal_handlers_disconnect_by_func (shell,
|
|
|
|
selection_window_state_event,
|
|
|
|
selection);
|
|
|
|
g_signal_handlers_disconnect_by_func (shell,
|
|
|
|
selection_visibility_notify_event,
|
|
|
|
selection);
|
2001-06-18 21:10:03 +08:00
|
|
|
|
2013-06-17 02:14:35 +08:00
|
|
|
selection_free_segs (selection);
|
2006-09-05 01:18:38 +08:00
|
|
|
|
2013-06-17 02:14:35 +08:00
|
|
|
g_slice_free (Selection, selection);
|
2006-09-05 01:18:38 +08:00
|
|
|
|
2013-06-17 02:14:35 +08:00
|
|
|
shell->selection = NULL;
|
2001-06-18 21:10:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-10-10 02:23:05 +08:00
|
|
|
gimp_display_shell_selection_undraw (GimpDisplayShell *shell)
|
2001-06-18 21:10:03 +08:00
|
|
|
{
|
2006-09-05 01:18:38 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
2013-06-17 02:14:35 +08:00
|
|
|
g_return_if_fail (shell->selection != NULL);
|
2006-09-05 01:18:38 +08:00
|
|
|
|
2013-06-17 02:14:35 +08:00
|
|
|
if (gimp_display_get_image (shell->display))
|
2001-06-18 21:10:03 +08:00
|
|
|
{
|
2010-10-10 02:23:05 +08:00
|
|
|
selection_undraw (shell->selection);
|
2001-06-18 21:10:03 +08:00
|
|
|
}
|
2010-10-10 02:23:05 +08:00
|
|
|
else
|
2008-03-20 00:15:50 +08:00
|
|
|
{
|
|
|
|
selection_stop (shell->selection);
|
|
|
|
selection_free_segs (shell->selection);
|
|
|
|
}
|
2001-06-18 21:10:03 +08:00
|
|
|
}
|
|
|
|
|
2010-10-10 02:23:05 +08:00
|
|
|
void
|
|
|
|
gimp_display_shell_selection_restart (GimpDisplayShell *shell)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
2013-06-17 02:14:35 +08:00
|
|
|
g_return_if_fail (shell->selection != NULL);
|
2010-10-10 02:23:05 +08:00
|
|
|
|
2013-06-17 02:14:35 +08:00
|
|
|
if (gimp_display_get_image (shell->display))
|
2010-10-10 02:23:05 +08:00
|
|
|
{
|
|
|
|
selection_start (shell->selection);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-09 20:26:33 +08:00
|
|
|
void
|
|
|
|
gimp_display_shell_selection_pause (GimpDisplayShell *shell)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
2013-06-17 02:14:35 +08:00
|
|
|
g_return_if_fail (shell->selection != NULL);
|
2010-10-09 20:26:33 +08:00
|
|
|
|
2013-06-17 02:14:35 +08:00
|
|
|
if (gimp_display_get_image (shell->display))
|
2010-10-09 20:26:33 +08:00
|
|
|
{
|
|
|
|
if (shell->selection->paused == 0)
|
|
|
|
selection_stop (shell->selection);
|
|
|
|
|
|
|
|
shell->selection->paused++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_display_shell_selection_resume (GimpDisplayShell *shell)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
2013-06-17 02:14:35 +08:00
|
|
|
g_return_if_fail (shell->selection != NULL);
|
2010-10-09 20:26:33 +08:00
|
|
|
|
2013-06-17 02:14:35 +08:00
|
|
|
if (gimp_display_get_image (shell->display))
|
2010-10-09 20:26:33 +08:00
|
|
|
{
|
|
|
|
shell->selection->paused--;
|
|
|
|
|
|
|
|
if (shell->selection->paused == 0)
|
|
|
|
selection_start (shell->selection);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-06-18 21:10:03 +08:00
|
|
|
void
|
2010-10-09 18:55:11 +08:00
|
|
|
gimp_display_shell_selection_set_show (GimpDisplayShell *shell,
|
|
|
|
gboolean show)
|
2001-06-18 21:10:03 +08:00
|
|
|
{
|
2006-09-05 01:18:38 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
2013-06-17 02:14:35 +08:00
|
|
|
g_return_if_fail (shell->selection != NULL);
|
2001-06-18 21:10:03 +08:00
|
|
|
|
2013-06-17 02:14:35 +08:00
|
|
|
if (gimp_display_get_image (shell->display))
|
2006-09-05 01:18:38 +08:00
|
|
|
{
|
2006-09-05 04:56:14 +08:00
|
|
|
Selection *selection = shell->selection;
|
2006-09-05 01:18:38 +08:00
|
|
|
|
2010-10-09 18:55:11 +08:00
|
|
|
if (show != selection->show_selection)
|
2006-09-05 01:18:38 +08:00
|
|
|
{
|
2006-09-05 04:56:14 +08:00
|
|
|
selection_undraw (selection);
|
2006-09-05 01:18:38 +08:00
|
|
|
|
2010-10-09 18:55:11 +08:00
|
|
|
selection->show_selection = show;
|
2006-09-05 01:18:38 +08:00
|
|
|
|
2006-09-22 22:27:07 +08:00
|
|
|
selection_start (selection);
|
2006-09-05 01:18:38 +08:00
|
|
|
}
|
|
|
|
}
|
2001-06-18 21:10:03 +08:00
|
|
|
}
|
|
|
|
|
2006-09-05 01:18:38 +08:00
|
|
|
|
|
|
|
/* private functions */
|
|
|
|
|
2006-09-05 02:22:50 +08:00
|
|
|
static void
|
2006-09-22 22:27:07 +08:00
|
|
|
selection_start (Selection *selection)
|
2006-09-05 02:22:50 +08:00
|
|
|
{
|
2006-09-05 04:56:14 +08:00
|
|
|
selection_stop (selection);
|
|
|
|
|
2008-01-24 02:11:29 +08:00
|
|
|
/* If this selection is paused, do not start it */
|
|
|
|
if (selection->paused == 0)
|
2006-09-05 02:22:50 +08:00
|
|
|
{
|
2006-09-05 15:09:56 +08:00
|
|
|
selection->timeout = g_idle_add ((GSourceFunc) selection_start_timeout,
|
|
|
|
selection);
|
2006-09-05 02:22:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-09-05 01:18:38 +08:00
|
|
|
static void
|
2006-09-05 04:56:14 +08:00
|
|
|
selection_stop (Selection *selection)
|
2001-06-18 21:10:03 +08:00
|
|
|
{
|
2006-09-05 04:56:14 +08:00
|
|
|
if (selection->timeout)
|
|
|
|
{
|
|
|
|
g_source_remove (selection->timeout);
|
|
|
|
selection->timeout = 0;
|
|
|
|
}
|
2001-06-18 21:10:03 +08:00
|
|
|
}
|
|
|
|
|
2006-09-05 01:18:38 +08:00
|
|
|
static void
|
2018-07-03 22:01:02 +08:00
|
|
|
selection_draw (Selection *selection,
|
|
|
|
cairo_t *cr)
|
2001-06-18 21:10:03 +08:00
|
|
|
{
|
2010-08-27 02:52:52 +08:00
|
|
|
if (selection->segs_in)
|
2010-08-27 00:09:33 +08:00
|
|
|
{
|
2010-08-27 21:03:03 +08:00
|
|
|
gimp_display_shell_draw_selection_in (selection->shell, cr,
|
|
|
|
selection->segs_in_mask,
|
|
|
|
selection->index % 8);
|
2010-08-27 00:09:33 +08:00
|
|
|
}
|
2006-09-05 02:22:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2006-09-05 04:56:14 +08:00
|
|
|
selection_undraw (Selection *selection)
|
2006-09-05 02:22:50 +08:00
|
|
|
{
|
2015-07-02 07:53:46 +08:00
|
|
|
gint x, y, w, h;
|
2006-09-05 02:22:50 +08:00
|
|
|
|
2006-09-22 22:27:07 +08:00
|
|
|
selection_stop (selection);
|
|
|
|
|
2015-07-02 07:53:46 +08:00
|
|
|
if (gimp_display_shell_mask_bounds (selection->shell, &x, &y, &w, &h))
|
2001-06-18 21:10:03 +08:00
|
|
|
{
|
2006-09-13 02:04:08 +08:00
|
|
|
/* expose will restart the selection */
|
2015-07-02 07:53:46 +08:00
|
|
|
gimp_display_shell_expose_area (selection->shell, x, y, w, h);
|
2001-06-18 21:10:03 +08:00
|
|
|
}
|
2006-09-13 02:04:08 +08:00
|
|
|
else
|
|
|
|
{
|
2006-09-22 22:27:07 +08:00
|
|
|
selection_start (selection);
|
2006-09-13 02:04:08 +08:00
|
|
|
}
|
2001-06-18 21:10:03 +08:00
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
static void
|
2010-08-27 02:52:52 +08:00
|
|
|
selection_render_mask (Selection *selection)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2011-04-16 07:35:35 +08:00
|
|
|
GdkWindow *window;
|
2011-05-08 04:33:05 +08:00
|
|
|
cairo_surface_t *surface;
|
|
|
|
cairo_t *cr;
|
|
|
|
|
2011-04-16 07:35:35 +08:00
|
|
|
window = gtk_widget_get_window (selection->shell->canvas);
|
|
|
|
surface = gdk_window_create_similar_surface (window, CAIRO_CONTENT_ALPHA,
|
|
|
|
gdk_window_get_width (window),
|
|
|
|
gdk_window_get_height (window));
|
|
|
|
cr = cairo_create (surface);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2010-09-23 20:26:52 +08:00
|
|
|
cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
|
2010-08-27 21:03:03 +08:00
|
|
|
cairo_set_line_width (cr, 1.0);
|
|
|
|
|
2013-04-19 22:22:19 +08:00
|
|
|
if (selection->shell->rotate_transform)
|
|
|
|
cairo_transform (cr, selection->shell->rotate_transform);
|
|
|
|
|
2018-03-07 17:38:58 +08:00
|
|
|
gimp_cairo_segments (cr,
|
|
|
|
selection->segs_in,
|
|
|
|
selection->n_segs_in);
|
2010-08-27 21:03:03 +08:00
|
|
|
cairo_stroke (cr);
|
2009-09-01 02:42:02 +08:00
|
|
|
|
2011-04-16 07:35:35 +08:00
|
|
|
selection->segs_in_mask = cairo_pattern_create_for_surface (surface);
|
2009-09-01 02:42:02 +08:00
|
|
|
|
2010-08-27 02:52:52 +08:00
|
|
|
cairo_destroy (cr);
|
2011-04-16 07:35:35 +08:00
|
|
|
cairo_surface_destroy (surface);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2010-08-25 07:58:00 +08:00
|
|
|
static void
|
2013-04-25 06:29:58 +08:00
|
|
|
selection_zoom_segs (Selection *selection,
|
|
|
|
const GimpBoundSeg *src_segs,
|
|
|
|
GimpSegment *dest_segs,
|
|
|
|
gint n_segs)
|
2010-08-25 07:58:00 +08:00
|
|
|
{
|
2010-08-27 03:01:39 +08:00
|
|
|
const gint xclamp = selection->shell->disp_width + 1;
|
|
|
|
const gint yclamp = selection->shell->disp_height + 1;
|
|
|
|
gint i;
|
2010-08-25 07:58:00 +08:00
|
|
|
|
2013-04-25 06:29:58 +08:00
|
|
|
gimp_display_shell_zoom_segments (selection->shell,
|
|
|
|
src_segs, dest_segs, n_segs,
|
|
|
|
0.0, 0.0);
|
2010-08-25 07:58:00 +08:00
|
|
|
|
|
|
|
for (i = 0; i < n_segs; i++)
|
|
|
|
{
|
2016-01-16 08:56:57 +08:00
|
|
|
if (! selection->shell->rotate_transform)
|
|
|
|
{
|
|
|
|
dest_segs[i].x1 = CLAMP (dest_segs[i].x1, -1, xclamp);
|
|
|
|
dest_segs[i].y1 = CLAMP (dest_segs[i].y1, -1, yclamp);
|
2010-08-25 07:58:00 +08:00
|
|
|
|
2016-01-16 08:56:57 +08:00
|
|
|
dest_segs[i].x2 = CLAMP (dest_segs[i].x2, -1, xclamp);
|
|
|
|
dest_segs[i].y2 = CLAMP (dest_segs[i].y2, -1, yclamp);
|
|
|
|
}
|
2010-08-25 07:58:00 +08:00
|
|
|
|
|
|
|
/* If this segment is a closing segment && the segments lie inside
|
|
|
|
* the region, OR if this is an opening segment and the segments
|
|
|
|
* lie outside the region...
|
|
|
|
* we need to transform it by one display pixel
|
|
|
|
*/
|
2010-08-27 03:01:39 +08:00
|
|
|
if (! src_segs[i].open)
|
2010-08-25 07:58:00 +08:00
|
|
|
{
|
|
|
|
/* If it is vertical */
|
|
|
|
if (dest_segs[i].x1 == dest_segs[i].x2)
|
|
|
|
{
|
|
|
|
dest_segs[i].x1 -= 1;
|
|
|
|
dest_segs[i].x2 -= 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dest_segs[i].y1 -= 1;
|
|
|
|
dest_segs[i].y2 -= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
static void
|
2006-09-05 04:56:14 +08:00
|
|
|
selection_generate_segs (Selection *selection)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2012-03-19 22:04:20 +08:00
|
|
|
GimpImage *image = gimp_display_get_image (selection->shell->display);
|
|
|
|
const GimpBoundSeg *segs_in;
|
|
|
|
const GimpBoundSeg *segs_out;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
/* Ask the image for the boundary of its selected region...
|
2010-10-15 18:37:36 +08:00
|
|
|
* Then transform that information into a new buffer of GimpSegments
|
1997-11-25 06:05:25 +08:00
|
|
|
*/
|
2009-09-01 02:57:52 +08:00
|
|
|
gimp_channel_boundary (gimp_image_get_mask (image),
|
2003-09-04 01:17:18 +08:00
|
|
|
&segs_in, &segs_out,
|
2010-08-24 23:36:42 +08:00
|
|
|
&selection->n_segs_in, &selection->n_segs_out,
|
2003-09-04 01:17:18 +08:00
|
|
|
0, 0, 0, 0);
|
2001-11-11 07:03:22 +08:00
|
|
|
|
2010-08-24 23:36:42 +08:00
|
|
|
if (selection->n_segs_in)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2010-10-15 18:37:36 +08:00
|
|
|
selection->segs_in = g_new (GimpSegment, selection->n_segs_in);
|
2013-04-25 06:29:58 +08:00
|
|
|
selection_zoom_segs (selection, segs_in,
|
|
|
|
selection->segs_in, selection->n_segs_in);
|
2001-12-01 00:39:40 +08:00
|
|
|
|
2010-08-27 02:52:52 +08:00
|
|
|
selection_render_mask (selection);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
else
|
2000-12-29 23:22:01 +08:00
|
|
|
{
|
2006-09-05 04:56:14 +08:00
|
|
|
selection->segs_in = NULL;
|
2000-12-29 23:22:01 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Possible secondary boundary representation */
|
2010-08-24 23:36:42 +08:00
|
|
|
if (selection->n_segs_out)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2010-10-15 18:37:36 +08:00
|
|
|
selection->segs_out = g_new (GimpSegment, selection->n_segs_out);
|
2013-04-25 06:29:58 +08:00
|
|
|
selection_zoom_segs (selection, segs_out,
|
|
|
|
selection->segs_out, selection->n_segs_out);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
else
|
2000-12-29 23:22:01 +08:00
|
|
|
{
|
2006-09-05 04:56:14 +08:00
|
|
|
selection->segs_out = NULL;
|
2000-12-29 23:22:01 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2006-09-05 04:56:14 +08:00
|
|
|
selection_free_segs (Selection *selection)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_pointer (&selection->segs_in, g_free);
|
|
|
|
selection->n_segs_in = 0;
|
2006-09-05 04:56:14 +08:00
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_pointer (&selection->segs_out, g_free);
|
|
|
|
selection->segs_out = NULL;
|
2005-10-18 23:27:56 +08:00
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_pointer (&selection->segs_in_mask, cairo_pattern_destroy);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2001-06-18 21:10:03 +08:00
|
|
|
static gboolean
|
2006-09-05 04:56:14 +08:00
|
|
|
selection_start_timeout (Selection *selection)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2006-09-22 22:27:07 +08:00
|
|
|
selection_free_segs (selection);
|
2008-03-19 05:22:21 +08:00
|
|
|
selection->timeout = 0;
|
|
|
|
|
2009-10-07 01:20:44 +08:00
|
|
|
if (! gimp_display_get_image (selection->shell->display))
|
2008-03-19 05:22:21 +08:00
|
|
|
return FALSE;
|
|
|
|
|
2006-09-22 22:27:07 +08:00
|
|
|
selection_generate_segs (selection);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2006-09-05 04:56:14 +08:00
|
|
|
selection->index = 0;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2003-11-11 22:50:07 +08:00
|
|
|
/* Draw the ants */
|
2010-10-09 18:55:11 +08:00
|
|
|
if (selection->show_selection)
|
2004-01-27 03:55:34 +08:00
|
|
|
{
|
2018-07-14 01:09:01 +08:00
|
|
|
GdkWindow *window;
|
|
|
|
GdkDrawingContext *context;
|
|
|
|
cairo_rectangle_int_t rect;
|
|
|
|
cairo_region_t *region;
|
|
|
|
cairo_t *cr;
|
2018-07-03 22:01:02 +08:00
|
|
|
|
2018-07-14 01:09:01 +08:00
|
|
|
window = gtk_widget_get_window (selection->shell->canvas);
|
|
|
|
|
|
|
|
rect.x = 0;
|
|
|
|
rect.y = 0;
|
|
|
|
rect.width = gdk_window_get_width (window);
|
|
|
|
rect.height = gdk_window_get_height (window);
|
|
|
|
|
|
|
|
region = cairo_region_create_rectangle (&rect);
|
|
|
|
context = gdk_window_begin_draw_frame (window, region);
|
|
|
|
cairo_region_destroy (region);
|
|
|
|
|
|
|
|
cr = gdk_drawing_context_get_cairo_context (context);
|
2006-09-05 02:22:50 +08:00
|
|
|
|
2018-07-03 22:01:02 +08:00
|
|
|
selection_draw (selection, cr);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2006-09-05 04:56:14 +08:00
|
|
|
if (selection->segs_out)
|
2010-08-27 00:09:33 +08:00
|
|
|
{
|
2013-04-19 22:22:19 +08:00
|
|
|
if (selection->shell->rotate_transform)
|
|
|
|
cairo_transform (cr, selection->shell->rotate_transform);
|
|
|
|
|
2010-08-27 02:52:52 +08:00
|
|
|
gimp_display_shell_draw_selection_out (selection->shell, cr,
|
|
|
|
selection->segs_out,
|
|
|
|
selection->n_segs_out);
|
2010-08-27 00:09:33 +08:00
|
|
|
}
|
2006-09-05 02:22:50 +08:00
|
|
|
|
2018-07-14 01:09:01 +08:00
|
|
|
gdk_window_end_draw_frame (window, context);
|
2018-07-03 22:01:02 +08:00
|
|
|
|
2010-10-09 18:51:20 +08:00
|
|
|
if (selection->segs_in && selection->shell_visible)
|
2018-07-14 01:09:01 +08:00
|
|
|
{
|
|
|
|
GimpDisplayConfig *config = selection->shell->display->config;
|
|
|
|
|
|
|
|
selection->timeout = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
|
|
|
|
config->marching_ants_speed,
|
|
|
|
(GSourceFunc) selection_timeout,
|
|
|
|
selection, NULL);
|
|
|
|
}
|
2006-09-05 02:22:50 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2001-06-18 21:10:03 +08:00
|
|
|
static gboolean
|
2006-09-05 04:56:14 +08:00
|
|
|
selection_timeout (Selection *selection)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2018-07-14 01:09:01 +08:00
|
|
|
GdkWindow *window;
|
|
|
|
GdkDrawingContext *context;
|
|
|
|
cairo_rectangle_int_t rect;
|
|
|
|
cairo_region_t *region;
|
|
|
|
cairo_t *cr;
|
2018-07-03 22:01:02 +08:00
|
|
|
|
2018-07-14 01:09:01 +08:00
|
|
|
window = gtk_widget_get_window (selection->shell->canvas);
|
|
|
|
|
|
|
|
rect.x = 0;
|
|
|
|
rect.y = 0;
|
|
|
|
rect.width = gdk_window_get_width (window);
|
|
|
|
rect.height = gdk_window_get_height (window);
|
|
|
|
|
|
|
|
region = cairo_region_create_rectangle (&rect);
|
|
|
|
context = gdk_window_begin_draw_frame (window, region);
|
|
|
|
cairo_region_destroy (region);
|
|
|
|
|
|
|
|
cr = gdk_drawing_context_get_cairo_context (context);
|
2018-07-03 22:01:02 +08:00
|
|
|
|
2006-09-05 04:56:14 +08:00
|
|
|
selection->index++;
|
2018-07-03 22:01:02 +08:00
|
|
|
selection_draw (selection, cr);
|
|
|
|
|
2018-07-14 01:09:01 +08:00
|
|
|
gdk_window_end_draw_frame (window, context);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
2006-09-05 04:56:14 +08:00
|
|
|
|
2006-09-05 05:23:50 +08:00
|
|
|
static void
|
2010-10-09 18:51:20 +08:00
|
|
|
selection_set_shell_visible (Selection *selection,
|
|
|
|
gboolean shell_visible)
|
2006-09-05 05:23:50 +08:00
|
|
|
{
|
2010-10-09 18:51:20 +08:00
|
|
|
if (selection->shell_visible != shell_visible)
|
2006-09-05 05:23:50 +08:00
|
|
|
{
|
2010-10-09 18:51:20 +08:00
|
|
|
selection->shell_visible = shell_visible;
|
2006-09-05 05:23:50 +08:00
|
|
|
|
2010-10-09 18:51:20 +08:00
|
|
|
if (shell_visible)
|
2006-09-22 22:27:07 +08:00
|
|
|
selection_start (selection);
|
2006-09-05 05:23:50 +08:00
|
|
|
else
|
|
|
|
selection_stop (selection);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
selection_window_state_event (GtkWidget *shell,
|
|
|
|
GdkEventWindowState *event,
|
|
|
|
Selection *selection)
|
|
|
|
{
|
2010-10-09 18:51:20 +08:00
|
|
|
selection_set_shell_visible (selection,
|
|
|
|
(event->new_window_state & (GDK_WINDOW_STATE_WITHDRAWN |
|
|
|
|
GDK_WINDOW_STATE_ICONIFIED)) == 0);
|
2006-09-05 05:23:50 +08:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
2007-12-29 07:13:46 +08:00
|
|
|
|
2006-09-05 04:56:14 +08:00
|
|
|
static gboolean
|
2006-09-05 05:11:14 +08:00
|
|
|
selection_visibility_notify_event (GtkWidget *shell,
|
|
|
|
GdkEventVisibility *event,
|
|
|
|
Selection *selection)
|
2006-09-05 04:56:14 +08:00
|
|
|
{
|
2010-10-09 18:51:20 +08:00
|
|
|
selection_set_shell_visible (selection,
|
|
|
|
event->state != GDK_VISIBILITY_FULLY_OBSCURED);
|
2006-09-05 04:56:14 +08:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|