~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

Viewing changes to app/tools/gimpregionselecttool.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070502163303-bvzhjzbpw8qglc4y
Tags: 2.3.16-1ubuntu1
* Resynchronized with Debian, remaining Ubuntu changes:
  - debian/rules: i18n magic.
* debian/control.in:
  - Maintainer: Ubuntu Core Developers <ubuntu-devel@lists.ubuntu.com>
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch,
  debian/patches/10_dont_show_wizard.patch: updated.
* debian/patches/04_composite-signedness.patch,
  debian/patches/05_add-letter-spacing.patch: dropped, used upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GIMP - The GNU Image Manipulation Program
 
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 
3
 *
 
4
 * gimpregionselecttool.c
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
 
 
23
#include <gtk/gtk.h>
 
24
 
 
25
#include "libgimpwidgets/gimpwidgets.h"
 
26
 
 
27
#include "tools-types.h"
 
28
 
 
29
#include "base/boundary.h"
 
30
#include "base/pixel-region.h"
 
31
 
 
32
#include "core/gimpchannel.h"
 
33
#include "core/gimpchannel-select.h"
 
34
#include "core/gimpimage.h"
 
35
#include "core/gimplayer-floating-sel.h"
 
36
 
 
37
#include "display/gimpcanvas.h"
 
38
#include "display/gimpdisplay.h"
 
39
#include "display/gimpdisplayshell.h"
 
40
#include "display/gimpdisplayshell-cursor.h"
 
41
#include "display/gimpdisplayshell-transform.h"
 
42
 
 
43
#include "gimpregionselecttool.h"
 
44
#include "gimpselectionoptions.h"
 
45
#include "gimptoolcontrol.h"
 
46
 
 
47
#include "gimp-intl.h"
 
48
 
 
49
 
 
50
static void   gimp_region_select_tool_finalize       (GObject               *object);
 
51
 
 
52
static void   gimp_region_select_tool_button_press   (GimpTool              *tool,
 
53
                                                      GimpCoords            *coords,
 
54
                                                      guint32                time,
 
55
                                                      GdkModifierType        state,
 
56
                                                      GimpDisplay           *display);
 
57
static void   gimp_region_select_tool_button_release (GimpTool              *tool,
 
58
                                                      GimpCoords            *coords,
 
59
                                                      guint32                time,
 
60
                                                      GdkModifierType        state,
 
61
                                                      GimpButtonReleaseType  release_type,
 
62
                                                      GimpDisplay           *display);
 
63
static void   gimp_region_select_tool_motion         (GimpTool              *tool,
 
64
                                                      GimpCoords            *coords,
 
65
                                                      guint32                time,
 
66
                                                      GdkModifierType        state,
 
67
                                                      GimpDisplay           *display);
 
68
static void   gimp_region_select_tool_cursor_update  (GimpTool              *tool,
 
69
                                                      GimpCoords            *coords,
 
70
                                                      GdkModifierType        state,
 
71
                                                      GimpDisplay           *display);
 
72
 
 
73
static void   gimp_region_select_tool_draw           (GimpDrawTool          *draw_tool);
 
74
 
 
75
static GdkSegment *gimp_region_select_tool_calculate (GimpRegionSelectTool  *region_sel,
 
76
                                                      GimpDisplay           *display,
 
77
                                                      gint                  *num_segs);
 
78
 
 
79
 
 
80
G_DEFINE_TYPE (GimpRegionSelectTool, gimp_region_select_tool,
 
81
               GIMP_TYPE_SELECTION_TOOL)
 
82
 
 
83
#define parent_class gimp_region_select_tool_parent_class
 
84
 
 
85
 
 
86
static void
 
87
gimp_region_select_tool_class_init (GimpRegionSelectToolClass *klass)
 
88
{
 
89
  GObjectClass      *object_class    = G_OBJECT_CLASS (klass);
 
90
  GimpToolClass     *tool_class      = GIMP_TOOL_CLASS (klass);
 
91
  GimpDrawToolClass *draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass);
 
92
 
 
93
  object_class->finalize     = gimp_region_select_tool_finalize;
 
94
 
 
95
  tool_class->button_press   = gimp_region_select_tool_button_press;
 
96
  tool_class->button_release = gimp_region_select_tool_button_release;
 
97
  tool_class->motion         = gimp_region_select_tool_motion;
 
98
  tool_class->cursor_update  = gimp_region_select_tool_cursor_update;
 
99
 
 
100
  draw_tool_class->draw      = gimp_region_select_tool_draw;
 
101
}
 
102
 
 
103
static void
 
104
gimp_region_select_tool_init (GimpRegionSelectTool *region_select)
 
105
{
 
106
  GimpTool *tool = GIMP_TOOL (region_select);
 
107
 
 
108
  gimp_tool_control_set_scroll_lock (tool->control, TRUE);
 
109
  gimp_tool_control_set_motion_mode (tool->control, GIMP_MOTION_MODE_COMPRESS);
 
110
 
 
111
  region_select->x               = 0;
 
112
  region_select->y               = 0;
 
113
  region_select->saved_threshold = 0.0;
 
114
 
 
115
  region_select->region_mask     = NULL;
 
116
  region_select->segs            = NULL;
 
117
  region_select->num_segs        = 0;
 
118
}
 
119
 
 
120
static void
 
121
gimp_region_select_tool_finalize (GObject *object)
 
122
{
 
123
  GimpRegionSelectTool *region_sel = GIMP_REGION_SELECT_TOOL (object);
 
124
 
 
125
  if (region_sel->region_mask)
 
126
    {
 
127
      g_object_unref (region_sel->region_mask);
 
128
      region_sel->region_mask = NULL;
 
129
    }
 
130
 
 
131
  if (region_sel->segs)
 
132
    {
 
133
      g_free (region_sel->segs);
 
134
      region_sel->segs     = NULL;
 
135
      region_sel->num_segs = 0;
 
136
    }
 
137
 
 
138
  G_OBJECT_CLASS (parent_class)->finalize (object);
 
139
}
 
140
 
 
141
static void
 
142
gimp_region_select_tool_button_press (GimpTool        *tool,
 
143
                                      GimpCoords      *coords,
 
144
                                      guint32          time,
 
145
                                      GdkModifierType  state,
 
146
                                      GimpDisplay     *display)
 
147
{
 
148
  GimpRegionSelectTool *region_sel = GIMP_REGION_SELECT_TOOL (tool);
 
149
  GimpSelectionOptions *options    = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
 
150
 
 
151
  region_sel->x               = coords->x;
 
152
  region_sel->y               = coords->y;
 
153
  region_sel->saved_threshold = options->threshold;
 
154
 
 
155
  gimp_tool_control_activate (tool->control);
 
156
  tool->display = display;
 
157
 
 
158
  if (gimp_selection_tool_start_edit (GIMP_SELECTION_TOOL (region_sel), coords))
 
159
    return;
 
160
 
 
161
  gimp_tool_push_status (tool, display,
 
162
                         _("Move the mouse to change threshold"));
 
163
 
 
164
  /*  calculate the region boundary  */
 
165
  region_sel->segs = gimp_region_select_tool_calculate (region_sel, display,
 
166
                                                        &region_sel->num_segs);
 
167
 
 
168
  gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), display);
 
169
}
 
170
 
 
171
static void
 
172
gimp_region_select_tool_button_release (GimpTool              *tool,
 
173
                                        GimpCoords            *coords,
 
174
                                        guint32                time,
 
175
                                        GdkModifierType        state,
 
176
                                        GimpButtonReleaseType  release_type,
 
177
                                        GimpDisplay           *display)
 
178
{
 
179
  GimpRegionSelectTool *region_sel = GIMP_REGION_SELECT_TOOL (tool);
 
180
  GimpSelectionOptions *options    = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
 
181
 
 
182
  gimp_tool_pop_status (tool, display);
 
183
 
 
184
  gimp_draw_tool_stop (GIMP_DRAW_TOOL (tool));
 
185
 
 
186
  gimp_tool_control_halt (tool->control);
 
187
 
 
188
  if (release_type != GIMP_BUTTON_RELEASE_CANCEL)
 
189
    {
 
190
      gint off_x, off_y;
 
191
 
 
192
      if (GIMP_SELECTION_TOOL (tool)->function == SELECTION_ANCHOR)
 
193
        {
 
194
          if (gimp_image_floating_sel (display->image))
 
195
            {
 
196
              /*  If there is a floating selection, anchor it  */
 
197
              floating_sel_anchor (gimp_image_floating_sel (display->image));
 
198
            }
 
199
          else
 
200
            {
 
201
              /*  Otherwise, clear the selection mask  */
 
202
              gimp_channel_clear (gimp_image_get_mask (display->image), NULL,
 
203
                                  TRUE);
 
204
            }
 
205
 
 
206
          gimp_image_flush (display->image);
 
207
        }
 
208
      else if (region_sel->region_mask)
 
209
        {
 
210
          if (options->sample_merged)
 
211
            {
 
212
              off_x = 0;
 
213
              off_y = 0;
 
214
            }
 
215
          else
 
216
            {
 
217
              GimpDrawable *drawable =
 
218
                gimp_image_active_drawable (display->image);
 
219
 
 
220
              gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y);
 
221
            }
 
222
 
 
223
          gimp_channel_select_channel (gimp_image_get_mask (display->image),
 
224
                                       GIMP_REGION_SELECT_TOOL_GET_CLASS (tool)->undo_desc,
 
225
                                       region_sel->region_mask,
 
226
                                       off_x,
 
227
                                       off_y,
 
228
                                       options->operation,
 
229
                                       options->feather,
 
230
                                       options->feather_radius,
 
231
                                       options->feather_radius);
 
232
 
 
233
 
 
234
          gimp_image_flush (display->image);
 
235
        }
 
236
    }
 
237
 
 
238
  if (region_sel->region_mask)
 
239
    {
 
240
      g_object_unref (region_sel->region_mask);
 
241
      region_sel->region_mask = NULL;
 
242
    }
 
243
 
 
244
  if (region_sel->segs)
 
245
    {
 
246
      g_free (region_sel->segs);
 
247
      region_sel->segs     = NULL;
 
248
      region_sel->num_segs = 0;
 
249
    }
 
250
 
 
251
  /*  Restore the original threshold  */
 
252
  g_object_set (options,
 
253
                "threshold", region_sel->saved_threshold,
 
254
                NULL);
 
255
}
 
256
 
 
257
static void
 
258
gimp_region_select_tool_motion (GimpTool        *tool,
 
259
                                GimpCoords      *coords,
 
260
                                guint32          time,
 
261
                                GdkModifierType  state,
 
262
                                GimpDisplay     *display)
 
263
{
 
264
  GimpRegionSelectTool *region_sel = GIMP_REGION_SELECT_TOOL (tool);
 
265
  GimpSelectionOptions *options    = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
 
266
  GdkSegment           *new_segs;
 
267
  gint                  num_new_segs;
 
268
  gint                  diff_x, diff_y;
 
269
  gdouble               diff;
 
270
 
 
271
  static guint32 last_time = 0;
 
272
 
 
273
  /* don't let the events come in too fast, ignore below a delay of 100 ms */
 
274
  if (time - last_time < 100)
 
275
    return;
 
276
 
 
277
  last_time = time;
 
278
 
 
279
  diff_x = coords->x - region_sel->x;
 
280
  diff_y = coords->y - region_sel->y;
 
281
 
 
282
  diff = ((ABS (diff_x) > ABS (diff_y)) ? diff_x : diff_y) / 2.0;
 
283
 
 
284
  g_object_set (options,
 
285
                "threshold", CLAMP (region_sel->saved_threshold + diff, 0, 255),
 
286
                NULL);
 
287
 
 
288
  /*  calculate the new region boundary  */
 
289
  new_segs = gimp_region_select_tool_calculate (region_sel, display,
 
290
                                                &num_new_segs);
 
291
 
 
292
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
 
293
 
 
294
  /*  make sure the XSegment array is freed before we assign the new one  */
 
295
  if (region_sel->segs)
 
296
    g_free (region_sel->segs);
 
297
 
 
298
  region_sel->segs     = new_segs;
 
299
  region_sel->num_segs = num_new_segs;
 
300
 
 
301
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
 
302
}
 
303
 
 
304
static void
 
305
gimp_region_select_tool_cursor_update (GimpTool        *tool,
 
306
                                       GimpCoords      *coords,
 
307
                                       GdkModifierType  state,
 
308
                                       GimpDisplay     *display)
 
309
{
 
310
  GimpSelectionOptions *options  = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
 
311
  GimpCursorModifier    modifier = GIMP_CURSOR_MODIFIER_NONE;
 
312
 
 
313
  if (! gimp_image_coords_in_active_pickable (display->image, coords,
 
314
                                              options->sample_merged, FALSE))
 
315
    modifier = GIMP_CURSOR_MODIFIER_BAD;
 
316
 
 
317
  gimp_tool_control_set_cursor_modifier (tool->control, modifier);
 
318
 
 
319
  GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
 
320
}
 
321
 
 
322
static void
 
323
gimp_region_select_tool_draw (GimpDrawTool *draw_tool)
 
324
{
 
325
  GimpRegionSelectTool *region_sel = GIMP_REGION_SELECT_TOOL (draw_tool);
 
326
 
 
327
  if (region_sel->segs)
 
328
    {
 
329
      GimpDisplayShell *shell;
 
330
 
 
331
      shell = GIMP_DISPLAY_SHELL (GIMP_TOOL (draw_tool)->display->shell);
 
332
 
 
333
      gimp_canvas_draw_segments (GIMP_CANVAS (shell->canvas),
 
334
                                 GIMP_CANVAS_STYLE_XOR,
 
335
                                 region_sel->segs, region_sel->num_segs);
 
336
    }
 
337
}
 
338
 
 
339
static GdkSegment *
 
340
gimp_region_select_tool_calculate (GimpRegionSelectTool *region_sel,
 
341
                                   GimpDisplay          *display,
 
342
                                   gint                 *num_segs)
 
343
{
 
344
  GimpTool             *tool    = GIMP_TOOL (region_sel);
 
345
  GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
 
346
  GimpDisplayShell     *shell   = GIMP_DISPLAY_SHELL (display->shell);
 
347
  GimpDrawable         *drawable;
 
348
  GdkSegment           *segs;
 
349
  BoundSeg             *bsegs;
 
350
  PixelRegion           maskPR;
 
351
 
 
352
  drawable = gimp_image_active_drawable (display->image);
 
353
 
 
354
  gimp_display_shell_set_override_cursor (shell, GDK_WATCH);
 
355
 
 
356
  if (region_sel->region_mask)
 
357
    g_object_unref (region_sel->region_mask);
 
358
 
 
359
  region_sel->region_mask =
 
360
    GIMP_REGION_SELECT_TOOL_GET_CLASS (region_sel)->get_mask (region_sel,
 
361
                                                              display);
 
362
 
 
363
  if (! region_sel->region_mask)
 
364
    {
 
365
      gimp_display_shell_unset_override_cursor (shell);
 
366
 
 
367
      *num_segs = 0;
 
368
      return NULL;
 
369
    }
 
370
 
 
371
  /*  calculate and allocate a new segment array which represents the
 
372
   *  boundary of the contiguous region
 
373
   */
 
374
  pixel_region_init (&maskPR,
 
375
                     gimp_drawable_get_tiles (GIMP_DRAWABLE (region_sel->region_mask)),
 
376
                     0, 0,
 
377
                     gimp_item_width  (GIMP_ITEM (region_sel->region_mask)),
 
378
                     gimp_item_height (GIMP_ITEM (region_sel->region_mask)),
 
379
                     FALSE);
 
380
 
 
381
  bsegs = boundary_find (&maskPR, BOUNDARY_WITHIN_BOUNDS,
 
382
                         0, 0,
 
383
                         gimp_item_width  (GIMP_ITEM (region_sel->region_mask)),
 
384
                         gimp_item_height (GIMP_ITEM (region_sel->region_mask)),
 
385
                         BOUNDARY_HALF_WAY,
 
386
                         num_segs);
 
387
 
 
388
  segs = g_new (GdkSegment, *num_segs);
 
389
 
 
390
  gimp_display_shell_transform_segments (shell, bsegs, segs, *num_segs,
 
391
                                         ! options->sample_merged);
 
392
  g_free (bsegs);
 
393
 
 
394
  gimp_display_shell_unset_override_cursor (shell);
 
395
 
 
396
  return segs;
 
397
}