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

« back to all changes in this revision

Viewing changes to app/tools/gimpiscissorstool.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
 
/* The GIMP -- an image manipulation program
 
1
/* GIMP - The GNU Image Manipulation Program
2
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3
3
 *
4
4
 * This program is free software; you can redistribute it and/or modify
34
34
 
35
35
/* The history of this implementation is lonog and varied.  It was
36
36
 * orignally done by Spencer and Peter, and worked fine in the 0.54
37
 
 * (motif only) release of the gimp.  Later revisions (0.99.something
 
37
 * (motif only) release of GIMP.  Later revisions (0.99.something
38
38
 * until about 1.1.4) completely changed the algorithm used, until it
39
39
 * bore little resemblance to the one described in the paper above.
40
40
 * The 0.54 version of the algorithm was then forwards ported to 1.1.4
66
66
#include "core/gimpchannel.h"
67
67
#include "core/gimpchannel-select.h"
68
68
#include "core/gimpimage.h"
69
 
#include "core/gimpprojection.h"
 
69
#include "core/gimppickable.h"
70
70
#include "core/gimpscanconvert.h"
71
71
#include "core/gimptoolinfo.h"
72
72
 
73
73
#include "widgets/gimphelp-ids.h"
 
74
#include "widgets/gimpwidgets-utils.h"
74
75
 
75
76
#include "display/gimpdisplay.h"
76
77
 
81
82
#include "gimp-intl.h"
82
83
 
83
84
 
84
 
/*  Other defines...  */
 
85
/*  defines  */
85
86
#define  MAX_GRADIENT      179.606  /* == sqrt (127^2 + 127^2) */
86
87
#define  GRADIENT_SEARCH   32  /* how far to look when snapping to an edge */
87
 
#define  TARGET_HEIGHT     25
88
 
#define  TARGET_WIDTH      25
89
 
#define  POINT_WIDTH       9   /* size (in pixels) of seed handles */
90
 
#define  POINT_HALFWIDTH   (POINT_WIDTH / 2)
 
88
#define  TARGET_SIZE       25
 
89
#define  POINT_WIDTH       12  /* size (in pixels) of seed handles */
91
90
#define  EXTEND_BY         0.2 /* proportion to expand cost map by */
92
91
#define  FIXED             5   /* additional fixed size to expand cost map */
93
92
#define  MIN_GRADIENT      63  /* gradients < this are directionless */
94
93
 
95
 
#define  MAX_POINTS        2048
96
 
 
97
 
#define  COST_WIDTH         2  /* number of bytes for each pixel in cost map  */
98
 
#define  BLOCK_WIDTH       64
99
 
#define  BLOCK_HEIGHT      64
100
 
#define  CONV_WIDTH        (BLOCK_WIDTH + 2)
101
 
#define  CONV_HEIGHT       (BLOCK_HEIGHT + 2)
 
94
#define  COST_WIDTH        2   /* number of bytes for each pixel in cost map  */
102
95
 
103
96
/* weight to give between gradient (_G) and direction (_D) */
104
97
#define  OMEGA_D           0.2
122
115
 
123
116
/*  local function prototypes  */
124
117
 
125
 
static void   gimp_iscissors_tool_class_init (GimpIscissorsToolClass *klass);
126
 
static void   gimp_iscissors_tool_init       (GimpIscissorsTool      *iscissors);
127
 
 
128
 
static void   gimp_iscissors_tool_finalize       (GObject           *object);
129
 
 
130
 
static void   gimp_iscissors_tool_control        (GimpTool          *tool,
131
 
                                                  GimpToolAction     action,
132
 
                                                  GimpDisplay       *gdisp);
133
 
static void   gimp_iscissors_tool_button_press   (GimpTool          *tool,
134
 
                                                  GimpCoords        *coords,
135
 
                                                  guint32            time,
136
 
                                                  GdkModifierType    state,
137
 
                                                  GimpDisplay       *gdisp);
138
 
static void   gimp_iscissors_tool_button_release (GimpTool          *tool,
139
 
                                                  GimpCoords        *coords,
140
 
                                                  guint32            time,
141
 
                                                  GdkModifierType    state,
142
 
                                                  GimpDisplay       *gdisp);
143
 
static void   gimp_iscissors_tool_motion         (GimpTool          *tool,
144
 
                                                  GimpCoords        *coords,
145
 
                                                  guint32            time,
146
 
                                                  GdkModifierType    state,
147
 
                                                  GimpDisplay       *gdisp);
148
 
static void   gimp_iscissors_tool_oper_update    (GimpTool          *tool,
149
 
                                                  GimpCoords        *coords,
150
 
                                                  GdkModifierType    state,
151
 
                                                  GimpDisplay       *gdisp);
152
 
static void   gimp_iscissors_tool_cursor_update  (GimpTool          *tool,
153
 
                                                  GimpCoords        *coords,
154
 
                                                  GdkModifierType    state,
155
 
                                                  GimpDisplay       *gdisp);
156
 
 
157
 
static void   gimp_iscissors_tool_reset          (GimpIscissorsTool *iscissors);
158
 
static void   gimp_iscissors_tool_draw           (GimpDrawTool      *draw_tool);
 
118
static void   gimp_iscissors_tool_finalize       (GObject               *object);
 
119
 
 
120
static void   gimp_iscissors_tool_control        (GimpTool              *tool,
 
121
                                                  GimpToolAction         action,
 
122
                                                  GimpDisplay           *display);
 
123
static void   gimp_iscissors_tool_button_press   (GimpTool              *tool,
 
124
                                                  GimpCoords            *coords,
 
125
                                                  guint32                time,
 
126
                                                  GdkModifierType        state,
 
127
                                                  GimpDisplay           *display);
 
128
static void   gimp_iscissors_tool_button_release (GimpTool              *tool,
 
129
                                                  GimpCoords            *coords,
 
130
                                                  guint32                time,
 
131
                                                  GdkModifierType        state,
 
132
                                                  GimpButtonReleaseType  release_type,
 
133
                                                  GimpDisplay           *display);
 
134
static void   gimp_iscissors_tool_motion         (GimpTool              *tool,
 
135
                                                  GimpCoords            *coords,
 
136
                                                  guint32                time,
 
137
                                                  GdkModifierType        state,
 
138
                                                  GimpDisplay           *display);
 
139
static void   gimp_iscissors_tool_oper_update    (GimpTool              *tool,
 
140
                                                  GimpCoords            *coords,
 
141
                                                  GdkModifierType        state,
 
142
                                                  gboolean               proximity,
 
143
                                                  GimpDisplay           *display);
 
144
static void   gimp_iscissors_tool_cursor_update  (GimpTool              *tool,
 
145
                                                  GimpCoords            *coords,
 
146
                                                  GdkModifierType        state,
 
147
                                                  GimpDisplay           *display);
 
148
static gboolean gimp_iscissors_tool_key_press    (GimpTool              *tool,
 
149
                                                  GdkEventKey           *kevent,
 
150
                                                  GimpDisplay           *display);
 
151
 
 
152
static void   gimp_iscissors_tool_apply          (GimpIscissorsTool     *iscissors,
 
153
                                                  GimpDisplay           *display);
 
154
static void   gimp_iscissors_tool_reset          (GimpIscissorsTool     *iscissors);
 
155
static void   gimp_iscissors_tool_draw           (GimpDrawTool          *draw_tool);
159
156
 
160
157
 
161
158
static void          iscissors_convert         (GimpIscissorsTool *iscissors,
162
 
                                                GimpDisplay       *gdisp);
163
 
static TileManager * gradient_map_new          (GimpImage         *gimage);
 
159
                                                GimpDisplay       *display);
 
160
static TileManager * gradient_map_new          (GimpImage         *image);
164
161
 
165
162
static void          find_optimal_path         (TileManager       *gradient_map,
166
 
                                                TempBuf           *dp_buf,
167
 
                                                gint               x1,
168
 
                                                gint               y1,
169
 
                                                gint               x2,
170
 
                                                gint               y2,
171
 
                                                gint               xs,
172
 
                                                gint               ys);
 
163
                                                TempBuf           *dp_buf,
 
164
                                                gint               x1,
 
165
                                                gint               y1,
 
166
                                                gint               x2,
 
167
                                                gint               y2,
 
168
                                                gint               xs,
 
169
                                                gint               ys);
173
170
static void          find_max_gradient         (GimpIscissorsTool *iscissors,
174
 
                                                GimpImage         *gimage,
175
 
                                                gint              *x,
176
 
                                                gint              *y);
 
171
                                                GimpImage         *image,
 
172
                                                gint              *x,
 
173
                                                gint              *y);
177
174
static void          calculate_curve           (GimpTool          *tool,
178
 
                                                ICurve            *curve);
 
175
                                                ICurve            *curve);
179
176
static void          iscissors_draw_curve      (GimpDrawTool      *draw_tool,
180
 
                                                ICurve            *curve);
 
177
                                                ICurve            *curve);
181
178
static void          iscissors_free_icurves    (GSList            *list);
182
 
static void          iscissors_free_buffers    (GimpIscissorsTool *iscissors);
183
179
 
184
180
static gint          mouse_over_vertex         (GimpIscissorsTool *iscissors,
185
 
                                                gdouble            x,
186
 
                                                gdouble            y);
187
 
static gboolean      clicked_on_vertex         (GimpTool          *tool);
 
181
                                                gdouble            x,
 
182
                                                gdouble            y);
 
183
static gboolean      clicked_on_vertex         (GimpIscissorsTool *iscissors,
 
184
                                                gdouble            x,
 
185
                                                gdouble            y);
188
186
static GSList      * mouse_over_curve          (GimpIscissorsTool *iscissors,
189
 
                                                gdouble            x,
190
 
                                                gdouble            y);
191
 
static gboolean      clicked_on_curve          (GimpTool          *tool);
 
187
                                                gdouble            x,
 
188
                                                gdouble            y);
 
189
static gboolean      clicked_on_curve          (GimpIscissorsTool *iscissors,
 
190
                                                gdouble            x,
 
191
                                                gdouble            y);
192
192
 
193
 
static void          precalculate_arrays       (void);
194
193
static GPtrArray   * plot_pixels               (GimpIscissorsTool *iscissors,
195
 
                                                TempBuf           *dp_buf,
196
 
                                                gint               x1,
197
 
                                                gint               y1,
198
 
                                                gint               xs,
199
 
                                                gint               ys,
200
 
                                                gint               xe,
201
 
                                                gint               ye);
 
194
                                                TempBuf           *dp_buf,
 
195
                                                gint               x1,
 
196
                                                gint               y1,
 
197
                                                gint               xs,
 
198
                                                gint               ys,
 
199
                                                gint               xe,
 
200
                                                gint               ye);
 
201
 
 
202
 
 
203
G_DEFINE_TYPE (GimpIscissorsTool, gimp_iscissors_tool,
 
204
               GIMP_TYPE_SELECTION_TOOL)
 
205
 
 
206
#define parent_class gimp_iscissors_tool_parent_class
202
207
 
203
208
 
204
209
/*  static variables  */
205
210
 
206
211
/*  where to move on a given link direction  */
207
 
static gint move[8][2] =
 
212
static const gint move[8][2] =
208
213
{
209
214
  {  1,  0 },
210
215
  {  0,  1 },
233
238
static guchar  maxgrad_conv2[TILE_WIDTH * TILE_HEIGHT * 4] = "";
234
239
 
235
240
 
236
 
static gfloat horz_deriv[9] =
 
241
static const gfloat horz_deriv[9] =
237
242
{
238
 
  1, 0, -1,
239
 
  2, 0, -2,
240
 
  1, 0, -1,
 
243
   1,  0, -1,
 
244
   2,  0, -2,
 
245
   1,  0, -1,
241
246
};
242
247
 
243
 
static gfloat vert_deriv[9] =
 
248
static const gfloat vert_deriv[9] =
244
249
{
245
 
  1, 2, 1,
246
 
  0, 0, 0,
 
250
   1,  2,  1,
 
251
   0,  0,  0,
247
252
  -1, -2, -1,
248
253
};
249
254
 
250
 
static gfloat blur_32[9] =
 
255
static const gfloat blur_32[9] =
251
256
{
252
 
  1, 1, 1,
253
 
  1, 24, 1,
254
 
  1, 1, 1,
 
257
   1,  1,  1,
 
258
   1, 24,  1,
 
259
   1,  1,  1,
255
260
};
256
261
 
257
 
static gfloat    distance_weights[GRADIENT_SEARCH * GRADIENT_SEARCH];
258
 
 
259
 
static gint      diagonal_weight[256];
260
 
static gint      direction_value[256][4];
261
 
static gboolean  initialized = FALSE;
262
 
static Tile     *cur_tile = NULL;
263
 
 
264
 
 
265
 
static GimpSelectionToolClass *parent_class = NULL;
 
262
static gfloat  distance_weights[GRADIENT_SEARCH * GRADIENT_SEARCH];
 
263
 
 
264
static gint    diagonal_weight[256];
 
265
static gint    direction_value[256][4];
 
266
static Tile   *cur_tile    = NULL;
266
267
 
267
268
 
268
269
void
275
276
                0,
276
277
                "gimp-iscissors-tool",
277
278
                _("Scissors"),
278
 
                _("Select shapes from image"),
 
279
                _("Scissors Select Tool: Select shapes using intelligent edge-fitting"),
279
280
                N_("Intelligent _Scissors"),
280
281
                "I",
281
282
                NULL, GIMP_HELP_TOOL_ISCISSORS,
283
284
                data);
284
285
}
285
286
 
286
 
GType
287
 
gimp_iscissors_tool_get_type (void)
288
 
{
289
 
  static GType tool_type = 0;
290
 
 
291
 
  if (! tool_type)
292
 
    {
293
 
      static const GTypeInfo tool_info =
294
 
      {
295
 
        sizeof (GimpIscissorsToolClass),
296
 
        (GBaseInitFunc) NULL,
297
 
        (GBaseFinalizeFunc) NULL,
298
 
        (GClassInitFunc) gimp_iscissors_tool_class_init,
299
 
        NULL,           /* class_finalize */
300
 
        NULL,           /* class_data     */
301
 
        sizeof (GimpIscissorsTool),
302
 
        0,              /* n_preallocs    */
303
 
        (GInstanceInitFunc) gimp_iscissors_tool_init,
304
 
      };
305
 
 
306
 
      tool_type = g_type_register_static (GIMP_TYPE_SELECTION_TOOL,
307
 
                                          "GimpIscissorsTool",
308
 
                                          &tool_info, 0);
309
 
    }
310
 
 
311
 
  return tool_type;
312
 
}
313
 
 
314
287
static void
315
288
gimp_iscissors_tool_class_init (GimpIscissorsToolClass *klass)
316
289
{
317
290
  GObjectClass      *object_class    = G_OBJECT_CLASS (klass);
318
291
  GimpToolClass     *tool_class      = GIMP_TOOL_CLASS (klass);
319
292
  GimpDrawToolClass *draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass);
320
 
 
321
 
  parent_class = g_type_class_peek_parent (klass);
 
293
  gint               i;
322
294
 
323
295
  object_class->finalize     = gimp_iscissors_tool_finalize;
324
296
 
328
300
  tool_class->motion         = gimp_iscissors_tool_motion;
329
301
  tool_class->oper_update    = gimp_iscissors_tool_oper_update;
330
302
  tool_class->cursor_update  = gimp_iscissors_tool_cursor_update;
 
303
  tool_class->key_press      = gimp_iscissors_tool_key_press;
331
304
 
332
305
  draw_tool_class->draw      = gimp_iscissors_tool_draw;
 
306
 
 
307
  for (i = 0; i < 256; i++)
 
308
    {
 
309
      /*  The diagonal weight array  */
 
310
      diagonal_weight[i] = (int) (i * G_SQRT2);
 
311
 
 
312
      /*  The direction value array  */
 
313
      direction_value[i][0] = (127 - abs (127 - i)) * 2;
 
314
      direction_value[i][1] = abs (127 - i) * 2;
 
315
      direction_value[i][2] = abs (191 - i) * 2;
 
316
      direction_value[i][3] = abs (63 - i) * 2;
 
317
    }
 
318
 
 
319
  /*  set the 256th index of the direction_values to the hightest cost  */
 
320
  direction_value[255][0] = 255;
 
321
  direction_value[255][1] = 255;
 
322
  direction_value[255][2] = 255;
 
323
  direction_value[255][3] = 255;
333
324
}
334
325
 
335
326
static void
368
359
static void
369
360
gimp_iscissors_tool_control (GimpTool       *tool,
370
361
                             GimpToolAction  action,
371
 
                             GimpDisplay    *gdisp)
 
362
                             GimpDisplay    *display)
372
363
{
373
364
  GimpIscissorsTool *iscissors = GIMP_ISCISSORS_TOOL (tool);
374
365
  IscissorsDraw      draw;
390
381
 
391
382
  iscissors->draw = draw;
392
383
 
393
 
  GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
 
384
  GIMP_TOOL_CLASS (parent_class)->control (tool, action, display);
394
385
 
395
386
  switch (action)
396
387
    {
397
 
    case PAUSE:
398
 
      break;
399
 
 
400
 
    case RESUME:
401
 
      break;
402
 
 
403
 
    case HALT:
 
388
    case GIMP_TOOL_ACTION_PAUSE:
 
389
    case GIMP_TOOL_ACTION_RESUME:
 
390
      break;
 
391
 
 
392
    case GIMP_TOOL_ACTION_HALT:
404
393
      gimp_iscissors_tool_reset (iscissors);
405
394
      break;
406
 
 
407
 
    default:
408
 
      break;
409
395
    }
410
396
}
411
397
 
414
400
                                  GimpCoords      *coords,
415
401
                                  guint32          time,
416
402
                                  GdkModifierType  state,
417
 
                                  GimpDisplay     *gdisp)
 
403
                                  GimpDisplay     *display)
418
404
{
419
405
  GimpIscissorsTool    *iscissors = GIMP_ISCISSORS_TOOL (tool);
420
 
  GimpSelectionOptions *options;
421
 
 
422
 
  options = GIMP_SELECTION_OPTIONS (tool->tool_info->tool_options);
423
 
 
424
 
  iscissors->x = coords->x;
425
 
  iscissors->y = coords->y;
 
406
  GimpSelectionOptions *options   = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
 
407
 
 
408
  iscissors->x = RINT (coords->x);
 
409
  iscissors->y = RINT (coords->y);
426
410
 
427
411
  /*  If the tool was being used in another image...reset it  */
428
412
 
429
413
  if (gimp_tool_control_is_active (tool->control))
430
414
    {
431
 
      if (gdisp != tool->gdisp)
 
415
      if (display != tool->display)
432
416
        {
433
417
          gimp_draw_tool_stop (GIMP_DRAW_TOOL (tool));
434
418
          gimp_iscissors_tool_reset (iscissors);
440
424
      gimp_tool_control_activate (tool->control);
441
425
    }
442
426
 
443
 
  tool->gdisp = gdisp;
 
427
  tool->display = display;
444
428
 
445
429
  switch (iscissors->state)
446
430
    {
449
433
      iscissors->draw  = DRAW_CURRENT_SEED;
450
434
 
451
435
      if (! (state & GDK_SHIFT_MASK))
452
 
        find_max_gradient (iscissors,
453
 
                           gdisp->gimage,
454
 
                           &iscissors->x,
 
436
        find_max_gradient (iscissors,
 
437
                           display->image,
 
438
                           &iscissors->x,
455
439
                           &iscissors->y);
456
440
 
457
 
      iscissors->x = CLAMP (iscissors->x, 0, gdisp->gimage->width - 1);
458
 
      iscissors->y = CLAMP (iscissors->y, 0, gdisp->gimage->height - 1);
 
441
      iscissors->x = CLAMP (iscissors->x, 0, display->image->width - 1);
 
442
      iscissors->y = CLAMP (iscissors->y, 0, display->image->height - 1);
459
443
 
460
444
      iscissors->ix = iscissors->x;
461
445
      iscissors->iy = iscissors->y;
462
446
 
463
447
      /*  Initialize the selection core only on starting the tool  */
464
 
      gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), gdisp);
 
448
      gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), display);
465
449
      break;
466
450
 
467
451
    default:
468
 
      /*  Check if the mouse click occured on a vertex or the curve itself  */
469
 
      if (clicked_on_vertex (tool))
470
 
        {
471
 
          iscissors->nx    = iscissors->x;
472
 
          iscissors->ny    = iscissors->y;
473
 
          iscissors->state = SEED_ADJUSTMENT;
 
452
      /*  Check if the mouse click occurred on a vertex or the curve itself  */
 
453
      if (clicked_on_vertex (iscissors, coords->x, coords->y))
 
454
        {
 
455
          iscissors->nx    = iscissors->x;
 
456
          iscissors->ny    = iscissors->y;
 
457
          iscissors->state = SEED_ADJUSTMENT;
474
458
 
475
 
          iscissors->draw = DRAW_CURVE | DRAW_ACTIVE_CURVE;
476
 
          gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
477
 
        }
 
459
          iscissors->draw = DRAW_CURVE | DRAW_ACTIVE_CURVE;
 
460
          gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
 
461
        }
478
462
      /*  If the iscissors is connected, check if the click was inside  */
479
463
      else if (iscissors->connected && iscissors->mask &&
480
 
               gimp_channel_value (iscissors->mask,
481
 
                                   iscissors->x,
482
 
                                   iscissors->y))
483
 
        {
484
 
          /*  Undraw the curve  */
485
 
          gimp_tool_control_halt (tool->control);
486
 
 
487
 
          iscissors->draw = DRAW_CURVE;
488
 
          gimp_draw_tool_stop (GIMP_DRAW_TOOL (tool));
489
 
 
490
 
          gimp_channel_select_channel (gimp_image_get_mask (gdisp->gimage),
491
 
                                       tool->tool_info->blurb,
492
 
                                       iscissors->mask,
493
 
                                       0, 0,
494
 
                                       GIMP_SELECTION_TOOL (tool)->op,
495
 
                                       options->feather,
496
 
                                       options->feather_radius,
497
 
                                       options->feather_radius);
498
 
 
499
 
          gimp_iscissors_tool_reset (iscissors);
500
 
 
501
 
          gimp_image_flush (gdisp->gimage);
502
 
        }
 
464
               gimp_pickable_get_opacity_at (GIMP_PICKABLE (iscissors->mask),
 
465
                                             iscissors->x,
 
466
                                             iscissors->y))
 
467
        {
 
468
          gimp_iscissors_tool_apply (iscissors, display);
 
469
        }
503
470
      else if (! iscissors->connected)
504
 
        {
 
471
        {
505
472
          /*  if we're not connected, we're adding a new point  */
506
473
 
507
474
          /*  pause the tool, but undraw nothing  */
508
475
          iscissors->draw = DRAW_NOTHING;
509
 
          gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
 
476
          gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
510
477
 
511
 
          iscissors->state = SEED_PLACEMENT;
512
 
          iscissors->draw  = DRAW_CURRENT_SEED;
 
478
          iscissors->state = SEED_PLACEMENT;
 
479
          iscissors->draw  = DRAW_CURRENT_SEED;
513
480
 
514
481
          if (options->interactive)
515
482
            iscissors->draw |= DRAW_LIVEWIRE;
516
483
 
517
 
          gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
518
 
        }
 
484
          gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
 
485
        }
519
486
      break;
520
487
    }
521
488
}
523
490
 
524
491
static void
525
492
iscissors_convert (GimpIscissorsTool *iscissors,
526
 
                   GimpDisplay       *gdisp)
 
493
                   GimpDisplay       *display)
527
494
{
528
 
  GimpSelectionOptions *options;
 
495
  GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (iscissors);
529
496
  GimpScanConvert      *sc;
530
497
  GimpVector2          *points;
531
498
  guint                 n_points;
532
499
  GSList               *list;
533
500
  ICurve               *icurve;
534
 
  guint                 packed;
535
501
  gint                  i;
536
502
  gint                  index;
537
503
 
538
 
  options =
539
 
    GIMP_SELECTION_OPTIONS (GIMP_TOOL (iscissors)->tool_info->tool_options);
540
 
 
541
504
  sc = gimp_scan_convert_new ();
542
505
 
543
506
  /* go over the curves in reverse order, adding the points we have */
552
515
      points   = g_new (GimpVector2, n_points);
553
516
 
554
517
      for (i = 0; i < n_points; i ++)
555
 
        {
556
 
          packed = GPOINTER_TO_INT (g_ptr_array_index (icurve->points, i));
557
 
          points[i].x = packed & 0x0000ffff;
558
 
          points[i].y = packed >> 16;
559
 
        }
 
518
        {
 
519
          guint32  packed = GPOINTER_TO_INT (g_ptr_array_index (icurve->points,
 
520
                                                                i));
 
521
 
 
522
          points[i].x = packed & 0x0000ffff;
 
523
          points[i].y = packed >> 16;
 
524
        }
560
525
 
561
526
      gimp_scan_convert_add_points (sc, n_points, points, FALSE);
562
527
      g_free (points);
565
530
  if (iscissors->mask)
566
531
    g_object_unref (iscissors->mask);
567
532
 
568
 
  iscissors->mask = gimp_channel_new_mask (gdisp->gimage,
569
 
                                           gdisp->gimage->width,
570
 
                                           gdisp->gimage->height);
 
533
  iscissors->mask = gimp_channel_new_mask (display->image,
 
534
                                           display->image->width,
 
535
                                           display->image->height);
571
536
  gimp_scan_convert_render (sc, GIMP_DRAWABLE (iscissors->mask)->tiles,
572
537
                            0, 0, options->antialias);
573
538
  gimp_scan_convert_free (sc);
574
539
}
575
540
 
576
541
static void
577
 
gimp_iscissors_tool_button_release (GimpTool        *tool,
578
 
                                    GimpCoords      *coords,
579
 
                                    guint32          time,
580
 
                                    GdkModifierType  state,
581
 
                                    GimpDisplay     *gdisp)
 
542
gimp_iscissors_tool_button_release (GimpTool              *tool,
 
543
                                    GimpCoords            *coords,
 
544
                                    guint32                time,
 
545
                                    GdkModifierType        state,
 
546
                                    GimpButtonReleaseType  release_type,
 
547
                                    GimpDisplay           *display)
582
548
{
583
549
  GimpIscissorsTool    *iscissors = GIMP_ISCISSORS_TOOL (tool);
584
 
  GimpSelectionOptions *options;
 
550
  GimpSelectionOptions *options   = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
585
551
  ICurve               *curve;
586
552
 
587
 
  options = GIMP_SELECTION_OPTIONS (tool->tool_info->tool_options);
588
 
 
589
553
  /* Make sure X didn't skip the button release event -- as it's known
590
554
   * to do
591
555
   */
598
562
    case SEED_PLACEMENT:
599
563
      iscissors->draw = DRAW_CURVE | DRAW_CURRENT_SEED;
600
564
      if (options->interactive)
601
 
        iscissors->draw |= DRAW_LIVEWIRE;
 
565
        iscissors->draw |= DRAW_LIVEWIRE;
602
566
      break;
603
567
    case SEED_ADJUSTMENT:
604
568
      iscissors->draw = DRAW_CURVE | DRAW_ACTIVE_CURVE;
609
573
 
610
574
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
611
575
 
612
 
  /*  First take care of the case where the user "cancels" the action  */
613
 
  if (! (state & GDK_BUTTON3_MASK))
 
576
  if (release_type != GIMP_BUTTON_RELEASE_CANCEL)
614
577
    {
615
578
      /*  Progress to the next stage of intelligent selection  */
616
579
      switch (iscissors->state)
617
 
        {
618
 
        case SEED_PLACEMENT:
619
 
          /*  Add a new icurve  */
620
 
          if (!iscissors->first_point)
621
 
            {
622
 
              /*  Determine if we're connecting to the first point  */
623
 
              if (iscissors->curves)
624
 
                {
625
 
                  curve = (ICurve *) iscissors->curves->data;
 
580
        {
 
581
        case SEED_PLACEMENT:
 
582
          /*  Add a new icurve  */
 
583
          if (!iscissors->first_point)
 
584
            {
 
585
              /*  Determine if we're connecting to the first point  */
 
586
              if (iscissors->curves)
 
587
                {
 
588
                  curve = (ICurve *) iscissors->curves->data;
626
589
 
627
 
                  if (gimp_draw_tool_on_handle (GIMP_DRAW_TOOL (tool), gdisp,
 
590
                  if (gimp_draw_tool_on_handle (GIMP_DRAW_TOOL (tool), display,
628
591
                                                iscissors->x, iscissors->y,
629
592
                                                GIMP_HANDLE_CIRCLE,
630
593
                                                curve->x1, curve->y1,
631
594
                                                POINT_WIDTH, POINT_WIDTH,
632
595
                                                GTK_ANCHOR_CENTER,
633
596
                                                FALSE))
634
 
                    {
635
 
                      iscissors->x = curve->x1;
636
 
                      iscissors->y = curve->y1;
637
 
                      iscissors->connected = TRUE;
 
597
                    {
 
598
                      iscissors->x = curve->x1;
 
599
                      iscissors->y = curve->y1;
 
600
                      iscissors->connected = TRUE;
638
601
                    }
639
 
                }
640
 
 
641
 
              /*  Create the new curve segment  */
642
 
              if (iscissors->ix != iscissors->x ||
643
 
                  iscissors->iy != iscissors->y)
644
 
                {
645
 
                  curve = g_new (ICurve, 1);
646
 
 
647
 
                  curve->x1 = iscissors->ix;
648
 
                  curve->y1 = iscissors->iy;
649
 
                  iscissors->ix = curve->x2 = iscissors->x;
650
 
                  iscissors->iy = curve->y2 = iscissors->y;
651
 
                  curve->points = NULL;
652
 
                  iscissors->curves = g_slist_append (iscissors->curves, curve);
653
 
                  calculate_curve (tool, curve);
654
 
                }
655
 
            }
656
 
          else /* this was our first point */
657
 
            {
658
 
              iscissors->first_point = FALSE;
659
 
            }
660
 
          break;
661
 
 
662
 
        case SEED_ADJUSTMENT:
663
 
          /*  recalculate both curves  */
664
 
          if (iscissors->curve1)
665
 
            {
666
 
              iscissors->curve1->x1 = iscissors->nx;
667
 
              iscissors->curve1->y1 = iscissors->ny;
668
 
              calculate_curve (tool, iscissors->curve1);
669
 
            }
670
 
          if (iscissors->curve2)
671
 
            {
672
 
              iscissors->curve2->x2 = iscissors->nx;
673
 
              iscissors->curve2->y2 = iscissors->ny;
674
 
              calculate_curve (tool, iscissors->curve2);
675
 
            }
676
 
          break;
677
 
 
678
 
        default:
679
 
          break;
680
 
        }
 
602
                }
 
603
 
 
604
              /*  Create the new curve segment  */
 
605
              if (iscissors->ix != iscissors->x ||
 
606
                  iscissors->iy != iscissors->y)
 
607
                {
 
608
                  curve = g_new (ICurve, 1);
 
609
 
 
610
                  curve->x1 = iscissors->ix;
 
611
                  curve->y1 = iscissors->iy;
 
612
                  iscissors->ix = curve->x2 = iscissors->x;
 
613
                  iscissors->iy = curve->y2 = iscissors->y;
 
614
                  curve->points = NULL;
 
615
                  iscissors->curves = g_slist_append (iscissors->curves, curve);
 
616
                  calculate_curve (tool, curve);
 
617
                }
 
618
            }
 
619
          else /* this was our first point */
 
620
            {
 
621
              iscissors->first_point = FALSE;
 
622
            }
 
623
          break;
 
624
 
 
625
        case SEED_ADJUSTMENT:
 
626
          /*  recalculate both curves  */
 
627
          if (iscissors->curve1)
 
628
            {
 
629
              iscissors->curve1->x1 = iscissors->nx;
 
630
              iscissors->curve1->y1 = iscissors->ny;
 
631
              calculate_curve (tool, iscissors->curve1);
 
632
            }
 
633
          if (iscissors->curve2)
 
634
            {
 
635
              iscissors->curve2->x2 = iscissors->nx;
 
636
              iscissors->curve2->y2 = iscissors->ny;
 
637
              calculate_curve (tool, iscissors->curve2);
 
638
            }
 
639
          break;
 
640
 
 
641
        default:
 
642
          break;
 
643
        }
681
644
    }
682
645
 
683
646
  iscissors->state = WAITING;
688
651
 
689
652
  /*  convert the curves into a region  */
690
653
  if (iscissors->connected)
691
 
    iscissors_convert (iscissors, gdisp);
 
654
    iscissors_convert (iscissors, display);
692
655
}
693
656
 
694
657
static void
696
659
                            GimpCoords      *coords,
697
660
                            guint32          time,
698
661
                            GdkModifierType  state,
699
 
                            GimpDisplay     *gdisp)
 
662
                            GimpDisplay     *display)
700
663
{
701
664
  GimpIscissorsTool    *iscissors = GIMP_ISCISSORS_TOOL (tool);
702
 
  GimpSelectionOptions *options;
703
 
 
704
 
  options = GIMP_SELECTION_OPTIONS (tool->tool_info->tool_options);
 
665
  GimpSelectionOptions *options   = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
705
666
 
706
667
  if (iscissors->state == NO_ACTION)
707
668
    return;
711
672
      iscissors->draw = DRAW_CURRENT_SEED;
712
673
 
713
674
      if (options->interactive)
714
 
        iscissors->draw |= DRAW_LIVEWIRE;
 
675
        iscissors->draw |= DRAW_LIVEWIRE;
715
676
    }
716
677
  else if (iscissors->state == SEED_ADJUSTMENT)
717
678
    {
720
681
 
721
682
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
722
683
 
723
 
  iscissors->x = coords->x;
724
 
  iscissors->y = coords->y;
 
684
  iscissors->x = RINT (coords->x);
 
685
  iscissors->y = RINT (coords->y);
725
686
 
726
687
  switch (iscissors->state)
727
688
    {
728
689
    case SEED_PLACEMENT:
729
690
      /*  Hold the shift key down to disable the auto-edge snap feature  */
730
691
      if (! (state & GDK_SHIFT_MASK))
731
 
        find_max_gradient (iscissors, gdisp->gimage,
732
 
                           &iscissors->x, &iscissors->y);
 
692
        find_max_gradient (iscissors, display->image,
 
693
                           &iscissors->x, &iscissors->y);
733
694
 
734
 
      iscissors->x = CLAMP (iscissors->x, 0, gdisp->gimage->width  - 1);
735
 
      iscissors->y = CLAMP (iscissors->y, 0, gdisp->gimage->height - 1);
 
695
      iscissors->x = CLAMP (iscissors->x, 0, display->image->width  - 1);
 
696
      iscissors->y = CLAMP (iscissors->y, 0, display->image->height - 1);
736
697
 
737
698
      if (iscissors->first_point)
738
 
        {
739
 
          iscissors->ix = iscissors->x;
740
 
          iscissors->iy = iscissors->y;
741
 
        }
 
699
        {
 
700
          iscissors->ix = iscissors->x;
 
701
          iscissors->iy = iscissors->y;
 
702
        }
742
703
      break;
743
704
 
744
705
    case SEED_ADJUSTMENT:
745
706
      /*  Move the current seed to the location of the cursor  */
746
707
      if (! (state & GDK_SHIFT_MASK))
747
 
        find_max_gradient (iscissors, gdisp->gimage,
748
 
                           &iscissors->x, &iscissors->y);
 
708
        find_max_gradient (iscissors, display->image,
 
709
                           &iscissors->x, &iscissors->y);
749
710
 
750
 
      iscissors->x = CLAMP (iscissors->x, 0, gdisp->gimage->width  - 1);
751
 
      iscissors->y = CLAMP (iscissors->y, 0, gdisp->gimage->height - 1);
 
711
      iscissors->x = CLAMP (iscissors->x, 0, display->image->width  - 1);
 
712
      iscissors->y = CLAMP (iscissors->y, 0, display->image->height - 1);
752
713
 
753
714
      iscissors->nx = iscissors->x;
754
715
      iscissors->ny = iscissors->y;
766
727
{
767
728
  GimpTool          *tool      = GIMP_TOOL (draw_tool);
768
729
  GimpIscissorsTool *iscissors = GIMP_ISCISSORS_TOOL (draw_tool);
769
 
  GimpDisplay       *gdisp;
 
730
  GimpDisplay       *display;
770
731
  ICurve            *curve;
771
732
  GSList            *list;
772
733
 
773
 
  gdisp = tool->gdisp;
 
734
  display = tool->display;
774
735
 
775
736
  /*  Draw the crosshairs target if we're placing a seed  */
776
737
  if (iscissors->draw & DRAW_CURRENT_SEED)
777
738
    {
778
739
      gimp_draw_tool_draw_handle (draw_tool,
779
740
                                  GIMP_HANDLE_CROSS,
780
 
                                  iscissors->x,
781
 
                                  iscissors->y,
782
 
                                  TARGET_WIDTH,
783
 
                                  TARGET_WIDTH,
 
741
                                  iscissors->x, iscissors->y,
 
742
                                  TARGET_SIZE, TARGET_SIZE,
784
743
                                  GTK_ANCHOR_CENTER,
785
744
                                  FALSE);
786
745
 
787
746
      /* Draw a line boundary */
788
747
      if (! iscissors->first_point && ! (iscissors->draw & DRAW_LIVEWIRE))
789
 
        {
 
748
        {
790
749
          gimp_draw_tool_draw_line (draw_tool,
791
750
                                    iscissors->ix, iscissors->iy,
792
751
                                    iscissors->x, iscissors->y,
793
752
                                    FALSE);
794
 
        }
 
753
        }
795
754
    }
796
755
 
797
756
  /* Draw the livewire boundary */
799
758
    {
800
759
      /* See if the mouse has moved.  If so, create a new segment... */
801
760
      if (! iscissors->livewire ||
802
 
          (iscissors->livewire &&
803
 
           (iscissors->ix != iscissors->livewire->x1 ||
804
 
            iscissors->x  != iscissors->livewire->x2  ||
805
 
            iscissors->iy != iscissors->livewire->y1 ||
806
 
            iscissors->y  != iscissors->livewire->y2)))
 
761
          (iscissors->livewire &&
 
762
           (iscissors->ix != iscissors->livewire->x1 ||
 
763
            iscissors->x  != iscissors->livewire->x2  ||
 
764
            iscissors->iy != iscissors->livewire->y1 ||
 
765
            iscissors->y  != iscissors->livewire->y2)))
807
766
        {
808
767
          curve = g_new (ICurve, 1);
809
768
 
821
780
              g_free (iscissors->livewire);
822
781
 
823
782
              iscissors->livewire = NULL;
824
 
            }
 
783
            }
825
784
 
826
785
          iscissors->livewire = curve;
827
786
          calculate_curve (tool, curve);
849
808
 
850
809
      /*  Go through the list of icurves, and render each one...  */
851
810
      for (list = iscissors->curves; list; list = g_slist_next (list))
852
 
        {
853
 
          curve = (ICurve *) list->data;
 
811
        {
 
812
          curve = (ICurve *) list->data;
854
813
 
855
814
          if (iscissors->draw & DRAW_ACTIVE_CURVE)
856
815
            {
875
834
                continue;
876
835
            }
877
836
 
878
 
          /*  plot the curve  */
879
 
          iscissors_draw_curve (draw_tool, curve);
880
 
        }
 
837
          /*  plot the curve  */
 
838
          iscissors_draw_curve (draw_tool, curve);
 
839
        }
881
840
    }
882
841
 
883
842
  if (iscissors->draw & DRAW_ACTIVE_CURVE)
884
843
    {
885
844
      /*  plot both curves, and the control point between them  */
886
845
      if (iscissors->curve1)
887
 
        {
 
846
        {
888
847
          gimp_draw_tool_draw_line (draw_tool,
889
848
                                    iscissors->curve1->x2,
890
849
                                    iscissors->curve1->y2,
891
850
                                    iscissors->nx,
892
851
                                    iscissors->ny,
893
852
                                    FALSE);
894
 
        }
 
853
        }
895
854
      if (iscissors->curve2)
896
 
        {
 
855
        {
897
856
          gimp_draw_tool_draw_line (draw_tool,
898
857
                                    iscissors->curve2->x1,
899
858
                                    iscissors->curve2->y1,
900
859
                                    iscissors->nx,
901
860
                                    iscissors->ny,
902
861
                                    FALSE);
903
 
        }
 
862
        }
904
863
 
905
864
      gimp_draw_tool_draw_handle (draw_tool,
906
865
                                  GIMP_HANDLE_FILLED_CIRCLE,
916
875
 
917
876
static void
918
877
iscissors_draw_curve (GimpDrawTool *draw_tool,
919
 
                      ICurve       *curve)
 
878
                      ICurve       *curve)
920
879
{
 
880
  gdouble  *points;
921
881
  gpointer *point;
922
 
  guint     len;
923
 
  gint      npts = 0;
924
 
  guint32   coords;
925
 
  guint32   coords_2;
 
882
  gint      i, len;
926
883
 
927
 
  /* Uh, this shouldn't happen, but it does.  So we ignore it.
928
 
   * Quality code, baby.
929
 
   */
930
884
  if (! curve->points)
931
885
    return;
932
886
 
933
 
  point = curve->points->pdata + 1;
934
 
  len   = curve->points->len - 1;
935
 
 
936
 
  while (len--)
 
887
  len = curve->points->len;
 
888
 
 
889
  points = g_new (gdouble, 2 * len);
 
890
 
 
891
  for (i = 0, point = curve->points->pdata; i < len; i++, point++)
937
892
    {
938
 
      coords   = GPOINTER_TO_INT (*point);
939
 
      coords_2 = GPOINTER_TO_INT (*(point - 1));
940
 
      point++;
 
893
      guint32 coords = GPOINTER_TO_INT (*point);
941
894
 
942
 
      if (npts < MAX_POINTS)
943
 
        {
944
 
          gimp_draw_tool_draw_line (draw_tool,
945
 
                                    (coords & 0x0000ffff),
946
 
                                    (coords >> 16),
947
 
                                    (coords_2 & 0x0000ffff),
948
 
                                    (coords_2 >> 16),
949
 
                                    FALSE);
950
 
          npts++;
951
 
        }
952
 
      else
953
 
        {
954
 
          g_warning ("too many points in ICurve segment!");
955
 
          return;
956
 
        }
 
895
      points[i * 2]     = (coords & 0x0000ffff);
 
896
      points[i * 2 + 1] = (coords >> 16);
957
897
    }
 
898
 
 
899
  gimp_draw_tool_draw_lines (draw_tool, points, len, FALSE, FALSE);
 
900
  g_free (points);
958
901
}
959
902
 
960
903
static void
961
904
gimp_iscissors_tool_oper_update (GimpTool        *tool,
962
905
                                 GimpCoords      *coords,
963
906
                                 GdkModifierType  state,
964
 
                                 GimpDisplay     *gdisp)
 
907
                                 gboolean         proximity,
 
908
                                 GimpDisplay     *display)
965
909
{
966
910
  GimpIscissorsTool *iscissors = GIMP_ISCISSORS_TOOL (tool);
967
911
 
968
 
  GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state, gdisp);
 
912
  GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state, proximity,
 
913
                                               display);
 
914
  /* parent sets a message in the status bar, but it will be replaced here */
969
915
 
970
 
  if (mouse_over_vertex (iscissors, coords->x, coords->y))
 
916
  if (mouse_over_vertex (iscissors, coords->x, coords->y) > 1)
971
917
    {
 
918
      gchar *status;
 
919
 
 
920
      status = gimp_suggest_modifiers (_("Click-Drag to move this point"),
 
921
                                       GDK_SHIFT_MASK & ~state,
 
922
                                       _("%s: disable auto-snap"), NULL, NULL);
 
923
      gimp_tool_replace_status (tool, display, status);
 
924
      g_free (status);
972
925
      iscissors->op = ISCISSORS_OP_MOVE_POINT;
973
926
    }
974
927
  else if (mouse_over_curve (iscissors, coords->x, coords->y))
975
928
    {
976
 
      iscissors->op = ISCISSORS_OP_ADD_POINT;
 
929
      ICurve *curve;
 
930
 
 
931
      curve = (ICurve *) iscissors->curves->data;
 
932
 
 
933
      if (gimp_draw_tool_on_handle (GIMP_DRAW_TOOL (tool), display,
 
934
                                    RINT (coords->x), RINT (coords->y),
 
935
                                    GIMP_HANDLE_CIRCLE,
 
936
                                    curve->x1, curve->y1,
 
937
                                    POINT_WIDTH, POINT_WIDTH,
 
938
                                    GTK_ANCHOR_CENTER,
 
939
                                    FALSE))
 
940
        {
 
941
          gimp_tool_replace_status (tool, display, _("Click to close the"
 
942
                                                     " curve"));
 
943
          iscissors->op = ISCISSORS_OP_CONNECT;
 
944
        }
 
945
      else
 
946
        {
 
947
          gimp_tool_replace_status (tool, display, _("Click to add a point"
 
948
                                                     " on this segment"));
 
949
          iscissors->op = ISCISSORS_OP_ADD_POINT;
 
950
        }
977
951
    }
978
952
  else if (iscissors->connected && iscissors->mask)
979
953
    {
980
 
      if (gimp_channel_value (iscissors->mask, coords->x, coords->y))
 
954
      if (gimp_pickable_get_opacity_at (GIMP_PICKABLE (iscissors->mask),
 
955
                                        RINT (coords->x),
 
956
                                        RINT (coords->y)))
981
957
        {
 
958
          if (proximity)
 
959
            {
 
960
              gimp_tool_replace_status (tool, display,
 
961
                                        _("Click or press Enter to convert to"
 
962
                                          " a selection"));
 
963
            }
982
964
          iscissors->op = ISCISSORS_OP_SELECT;
983
965
        }
984
966
      else
985
967
        {
 
968
          if (proximity)
 
969
            {
 
970
              gimp_tool_replace_status (tool, display,
 
971
                                        _("Press Enter to convert to a"
 
972
                                          " selection"));
 
973
            }
986
974
          iscissors->op = ISCISSORS_OP_IMPOSSIBLE;
987
975
        }
988
976
    }
989
977
  else
990
978
    {
991
979
      switch (iscissors->state)
992
 
        {
993
 
        case WAITING:
 
980
        {
 
981
        case WAITING:
 
982
          if (proximity)
 
983
            {
 
984
              gchar *status;
 
985
 
 
986
              status = gimp_suggest_modifiers (_("Click or Click-Drag to add a"
 
987
                                                 " point"),
 
988
                                               GDK_SHIFT_MASK & ~state,
 
989
                                               _("%s: disable auto-snap"),
 
990
                                               NULL, NULL);
 
991
              gimp_tool_replace_status (tool, display, status);
 
992
              g_free (status);
 
993
            }
994
994
          iscissors->op = ISCISSORS_OP_ADD_POINT;
995
 
          break;
 
995
          break;
996
996
 
997
 
        case SEED_PLACEMENT:
998
 
        case SEED_ADJUSTMENT:
999
 
        default:
 
997
        default:
 
998
          /* if NO_ACTION, keep parent's status bar message (selection tool) */
1000
999
          iscissors->op = ISCISSORS_OP_NONE;
1001
1000
          break;
1002
 
        }
 
1001
        }
1003
1002
    }
1004
1003
}
1005
1004
 
1007
1006
gimp_iscissors_tool_cursor_update (GimpTool        *tool,
1008
1007
                                   GimpCoords      *coords,
1009
1008
                                   GdkModifierType  state,
1010
 
                                   GimpDisplay     *gdisp)
 
1009
                                   GimpDisplay     *display)
1011
1010
{
1012
1011
  GimpIscissorsTool  *iscissors = GIMP_ISCISSORS_TOOL (tool);
1013
 
  GimpCursorType      cursor    = GIMP_CURSOR_MOUSE;
1014
1012
  GimpCursorModifier  modifier  = GIMP_CURSOR_MODIFIER_NONE;
1015
1013
 
1016
1014
  switch (iscissors->op)
1017
1015
    {
1018
1016
    case ISCISSORS_OP_SELECT:
1019
 
      GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, gdisp);
 
1017
      GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords,
 
1018
                                                     state, display);
1020
1019
      return;
 
1020
 
1021
1021
    case ISCISSORS_OP_MOVE_POINT:
1022
1022
      modifier = GIMP_CURSOR_MODIFIER_MOVE;
1023
1023
      break;
 
1024
 
1024
1025
    case ISCISSORS_OP_ADD_POINT:
1025
1026
      modifier = GIMP_CURSOR_MODIFIER_PLUS;
1026
1027
      break;
 
1028
 
 
1029
    case ISCISSORS_OP_CONNECT:
 
1030
      modifier = GIMP_CURSOR_MODIFIER_JOIN;
 
1031
      break;
 
1032
 
1027
1033
    case ISCISSORS_OP_IMPOSSIBLE:
1028
 
      cursor = GIMP_CURSOR_BAD;
1029
 
      break;
1030
 
    default:
1031
 
      break;
1032
 
    }
1033
 
 
1034
 
  gimp_tool_set_cursor (tool, gdisp,
1035
 
                        cursor, GIMP_TOOL_CURSOR_ISCISSORS, modifier);
1036
 
}
1037
 
 
 
1034
      modifier = GIMP_CURSOR_MODIFIER_BAD;
 
1035
      break;
 
1036
 
 
1037
    default:
 
1038
      break;
 
1039
    }
 
1040
 
 
1041
  gimp_tool_set_cursor (tool, display,
 
1042
                        GIMP_CURSOR_MOUSE,
 
1043
                        GIMP_TOOL_CURSOR_ISCISSORS,
 
1044
                        modifier);
 
1045
}
 
1046
 
 
1047
static gboolean
 
1048
gimp_iscissors_tool_key_press (GimpTool    *tool,
 
1049
                               GdkEventKey *kevent,
 
1050
                               GimpDisplay *display)
 
1051
{
 
1052
  GimpIscissorsTool *iscissors = GIMP_ISCISSORS_TOOL (tool);
 
1053
 
 
1054
  if (display != tool->display)
 
1055
    return FALSE;
 
1056
 
 
1057
  switch (kevent->keyval)
 
1058
    {
 
1059
    case GDK_KP_Enter:
 
1060
    case GDK_Return:
 
1061
      if (iscissors->connected && iscissors->mask)
 
1062
        {
 
1063
          gimp_iscissors_tool_apply (iscissors, display);
 
1064
          return TRUE;
 
1065
        }
 
1066
      return FALSE;
 
1067
 
 
1068
    case GDK_Escape:
 
1069
      gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
 
1070
      return TRUE;
 
1071
 
 
1072
    default:
 
1073
      return FALSE;
 
1074
    }
 
1075
}
 
1076
 
 
1077
static void
 
1078
gimp_iscissors_tool_apply (GimpIscissorsTool *iscissors,
 
1079
                           GimpDisplay       *display)
 
1080
{
 
1081
  GimpTool             *tool    = GIMP_TOOL (iscissors);
 
1082
  GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
 
1083
 
 
1084
  /*  Undraw the curve  */
 
1085
  gimp_tool_control_halt (tool->control);
 
1086
 
 
1087
  iscissors->draw = DRAW_CURVE;
 
1088
  gimp_draw_tool_stop (GIMP_DRAW_TOOL (tool));
 
1089
 
 
1090
  gimp_channel_select_channel (gimp_image_get_mask (display->image),
 
1091
                               tool->tool_info->blurb,
 
1092
                               iscissors->mask,
 
1093
                               0, 0,
 
1094
                               options->operation,
 
1095
                               options->feather,
 
1096
                               options->feather_radius,
 
1097
                               options->feather_radius);
 
1098
 
 
1099
  gimp_iscissors_tool_reset (iscissors);
 
1100
 
 
1101
  gimp_image_flush (display->image);
 
1102
}
1038
1103
 
1039
1104
static void
1040
1105
gimp_iscissors_tool_reset (GimpIscissorsTool *iscissors)
1059
1124
    {
1060
1125
      /* release any tile we were using */
1061
1126
      if (cur_tile)
1062
 
        {
1063
 
          tile_release (cur_tile, FALSE);
 
1127
        {
 
1128
          tile_release (cur_tile, FALSE);
1064
1129
          cur_tile = NULL;
1065
1130
        }
1066
1131
 
1076
1141
  iscissors->state       = NO_ACTION;
1077
1142
 
1078
1143
  /*  Reset the dp buffers  */
1079
 
  iscissors_free_buffers (iscissors);
1080
 
 
1081
 
  /*  If they haven't already been initialized, precalculate the diagonal
1082
 
   *  weight and direction value arrays
1083
 
   */
1084
 
  if (!initialized)
 
1144
  if (iscissors->dp_buf)
1085
1145
    {
1086
 
      precalculate_arrays ();
1087
 
      initialized = TRUE;
 
1146
      temp_buf_free (iscissors->dp_buf);
 
1147
      iscissors->dp_buf = NULL;
1088
1148
    }
1089
1149
}
1090
1150
 
1098
1158
    {
1099
1159
      curve = (ICurve *) list->data;
1100
1160
      if (curve->points)
1101
 
        g_ptr_array_free (curve->points, TRUE);
 
1161
        g_ptr_array_free (curve->points, TRUE);
1102
1162
 
1103
1163
      g_free (curve);
1104
1164
      list = g_slist_next (list);
1106
1166
}
1107
1167
 
1108
1168
 
1109
 
static void
1110
 
iscissors_free_buffers (GimpIscissorsTool *iscissors)
1111
 
{
1112
 
  if (iscissors->dp_buf)
1113
 
    temp_buf_free (iscissors->dp_buf);
1114
 
 
1115
 
  iscissors->dp_buf = NULL;
1116
 
}
1117
 
 
1118
 
 
1119
1169
/* XXX need some scan-conversion routines from somewhere.  maybe. ? */
1120
1170
 
1121
1171
static gint
1122
1172
mouse_over_vertex (GimpIscissorsTool *iscissors,
1123
 
                   gdouble            x,
1124
 
                   gdouble            y)
 
1173
                   gdouble            x,
 
1174
                   gdouble            y)
1125
1175
{
1126
1176
  GSList *list;
1127
 
  ICurve *curve;
1128
1177
  gint    curves_found = 0;
1129
1178
 
1130
1179
  /*  traverse through the list, returning non-zero if the current cursor
1138
1187
 
1139
1188
  while (list && curves_found < 2)
1140
1189
    {
1141
 
      curve = (ICurve *) list->data;
 
1190
      ICurve *curve = list->data;
1142
1191
 
1143
1192
      if (gimp_draw_tool_on_handle (GIMP_DRAW_TOOL (iscissors),
1144
 
                                    GIMP_TOOL (iscissors)->gdisp,
 
1193
                                    GIMP_TOOL (iscissors)->display,
1145
1194
                                    x, y,
1146
1195
                                    GIMP_HANDLE_CIRCLE,
1147
1196
                                    curve->x1, curve->y1,
1148
1197
                                    POINT_WIDTH, POINT_WIDTH,
1149
1198
                                    GTK_ANCHOR_CENTER,
1150
1199
                                    FALSE))
1151
 
        {
1152
 
          iscissors->curve1 = curve;
 
1200
        {
 
1201
          iscissors->curve1 = curve;
1153
1202
 
1154
 
          if (curves_found++)
1155
 
            return curves_found;
1156
 
        }
 
1203
          if (curves_found++)
 
1204
            return curves_found;
 
1205
        }
1157
1206
      else if (gimp_draw_tool_on_handle (GIMP_DRAW_TOOL (iscissors),
1158
 
                                         GIMP_TOOL (iscissors)->gdisp,
 
1207
                                         GIMP_TOOL (iscissors)->display,
1159
1208
                                         x, y,
1160
1209
                                         GIMP_HANDLE_CIRCLE,
1161
1210
                                         curve->x2, curve->y2,
1162
1211
                                         POINT_WIDTH, POINT_WIDTH,
1163
1212
                                         GTK_ANCHOR_CENTER,
1164
1213
                                         FALSE))
1165
 
        {
1166
 
          iscissors->curve2 = curve;
 
1214
        {
 
1215
          iscissors->curve2 = curve;
1167
1216
 
1168
 
          if (curves_found++)
1169
 
            return curves_found;
1170
 
        }
 
1217
          if (curves_found++)
 
1218
            return curves_found;
 
1219
        }
1171
1220
 
1172
1221
      list = g_slist_next (list);
1173
1222
    }
1176
1225
}
1177
1226
 
1178
1227
static gboolean
1179
 
clicked_on_vertex (GimpTool *tool)
 
1228
clicked_on_vertex (GimpIscissorsTool *iscissors,
 
1229
                   gdouble            x,
 
1230
                   gdouble            y)
1180
1231
{
1181
 
  GimpIscissorsTool *iscissors    = GIMP_ISCISSORS_TOOL (tool);
1182
 
  gint               curves_found = 0;
 
1232
  gint curves_found = 0;
1183
1233
 
1184
 
  curves_found = mouse_over_vertex (iscissors, iscissors->x, iscissors->y);
 
1234
  curves_found = mouse_over_vertex (iscissors, x, y);
1185
1235
 
1186
1236
  if (curves_found > 1)
1187
1237
    {
1188
1238
      /*  undraw the curve  */
1189
1239
      iscissors->draw = DRAW_CURVE;
1190
 
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
 
1240
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (iscissors));
1191
1241
 
1192
1242
      return TRUE;
1193
1243
    }
1199
1249
  if (curves_found == 1)
1200
1250
    return FALSE;
1201
1251
 
1202
 
  return clicked_on_curve (tool);
 
1252
  return clicked_on_curve (iscissors, x, y);
1203
1253
}
1204
1254
 
1205
1255
 
1206
1256
static GSList *
1207
1257
mouse_over_curve (GimpIscissorsTool *iscissors,
1208
 
                  gdouble            x,
1209
 
                  gdouble            y)
 
1258
                  gdouble            x,
 
1259
                  gdouble            y)
1210
1260
{
1211
 
  GSList   *list;
1212
 
  gpointer *pt;
1213
 
  gint      len;
1214
 
  ICurve   *curve;
1215
 
  guint32   coords;
1216
 
  gint      tx, ty;
 
1261
  GSList *list;
1217
1262
 
1218
1263
  /*  traverse through the list, returning the curve segment's list element
1219
1264
   *  if the current cursor position is on a curve...
1220
1265
   */
1221
 
 
1222
1266
  for (list = iscissors->curves; list; list = g_slist_next (list))
1223
1267
    {
1224
 
      curve = (ICurve *) list->data;
 
1268
      ICurve   *curve = list->data;
 
1269
      gpointer *pt;
 
1270
      gint      len;
1225
1271
 
1226
1272
      pt = curve->points->pdata;
1227
1273
      len = curve->points->len;
 
1274
 
1228
1275
      while (len--)
1229
 
        {
1230
 
          coords = GPOINTER_TO_INT (*pt);
1231
 
          pt++;
1232
 
          tx = coords & 0x0000ffff;
1233
 
          ty = coords >> 16;
1234
 
 
1235
 
          /*  Is the specified point close enough to the curve?  */
1236
 
          if (gimp_draw_tool_in_radius (GIMP_DRAW_TOOL (iscissors),
1237
 
                                        GIMP_TOOL (iscissors)->gdisp,
 
1276
        {
 
1277
          guint32 coords = GPOINTER_TO_INT (*pt);
 
1278
          gint    tx, ty;
 
1279
 
 
1280
          pt++;
 
1281
          tx = coords & 0x0000ffff;
 
1282
          ty = coords >> 16;
 
1283
 
 
1284
          /*  Is the specified point close enough to the curve?  */
 
1285
          if (gimp_draw_tool_in_radius (GIMP_DRAW_TOOL (iscissors),
 
1286
                                        GIMP_TOOL (iscissors)->display,
1238
1287
                                        tx, ty,
1239
1288
                                        x, y,
1240
 
                                        POINT_HALFWIDTH))
1241
 
            {
1242
 
              return list;
1243
 
            }
1244
 
        }
 
1289
                                        POINT_WIDTH / 2))
 
1290
            {
 
1291
              return list;
 
1292
            }
 
1293
        }
1245
1294
    }
1246
1295
 
1247
1296
  return NULL;
1248
1297
}
1249
1298
 
1250
1299
static gboolean
1251
 
clicked_on_curve (GimpTool *tool)
 
1300
clicked_on_curve (GimpIscissorsTool *iscissors,
 
1301
                  gdouble            x,
 
1302
                  gdouble            y)
1252
1303
{
1253
 
  GimpIscissorsTool    *iscissors;
1254
 
  GimpSelectionOptions *options;
1255
 
  GSList               *list, *new_link;
1256
 
  ICurve               *curve, *new_curve;
1257
 
 
1258
 
  iscissors = GIMP_ISCISSORS_TOOL (tool);
1259
 
  options   = GIMP_SELECTION_OPTIONS (tool->tool_info->tool_options);
 
1304
  GSList *list;
1260
1305
 
1261
1306
  /*  traverse through the list, getting back the curve segment's list
1262
1307
   *  element if the current cursor position is on a curve...
1263
1308
   *  If this occurs, replace the curve with two new curves,
1264
1309
   *  separated by a new vertex.
1265
1310
   */
1266
 
  list = mouse_over_curve (iscissors, iscissors->x, iscissors->y);
 
1311
  list = mouse_over_curve (iscissors, x, y);
1267
1312
 
1268
1313
  if (list)
1269
1314
    {
1270
 
      curve = (ICurve *) list->data;
 
1315
      ICurve *curve = list->data;
 
1316
      ICurve *new_curve;
 
1317
      GSList *new_link;
1271
1318
 
1272
1319
      /*  undraw the curve  */
1273
1320
      iscissors->draw = DRAW_CURVE;
1274
 
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
 
1321
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (iscissors));
1275
1322
 
1276
1323
      /*  Create the new curve  */
1277
1324
      new_curve = g_new (ICurve, 1);
1301
1348
 
1302
1349
 
1303
1350
static void
1304
 
precalculate_arrays (void)
1305
 
{
1306
 
  gint i;
1307
 
 
1308
 
  for (i = 0; i < 256; i++)
1309
 
    {
1310
 
      /*  The diagonal weight array  */
1311
 
      diagonal_weight[i] = (int) (i * G_SQRT2);
1312
 
 
1313
 
      /*  The direction value array  */
1314
 
      direction_value[i][0] = (127 - abs (127 - i)) * 2;
1315
 
      direction_value[i][1] = abs (127 - i) * 2;
1316
 
      direction_value[i][2] = abs (191 - i) * 2;
1317
 
      direction_value[i][3] = abs (63 - i) * 2;
1318
 
    }
1319
 
 
1320
 
  /*  set the 256th index of the direction_values to the hightest cost  */
1321
 
  direction_value[255][0] = 255;
1322
 
  direction_value[255][1] = 255;
1323
 
  direction_value[255][2] = 255;
1324
 
  direction_value[255][3] = 255;
1325
 
}
1326
 
 
1327
 
 
1328
 
static void
1329
1351
calculate_curve (GimpTool *tool,
1330
 
                 ICurve   *curve)
 
1352
                 ICurve   *curve)
1331
1353
{
1332
1354
  GimpIscissorsTool *iscissors;
1333
 
  GimpDisplay       *gdisp;
 
1355
  GimpDisplay       *display;
1334
1356
  gint               x, y, dir;
1335
1357
  gint               xs, ys, xe, ye;
1336
1358
  gint               x1, y1, x2, y2;
1349
1371
 
1350
1372
  iscissors = GIMP_ISCISSORS_TOOL (tool);
1351
1373
 
1352
 
  gdisp = tool->gdisp;
 
1374
  display = tool->display;
1353
1375
 
1354
1376
  /*  Get the bounding box  */
1355
 
  xs = CLAMP (curve->x1, 0, gdisp->gimage->width - 1);
1356
 
  ys = CLAMP (curve->y1, 0, gdisp->gimage->height - 1);
1357
 
  xe = CLAMP (curve->x2, 0, gdisp->gimage->width - 1);
1358
 
  ye = CLAMP (curve->y2, 0, gdisp->gimage->height - 1);
 
1377
  xs = CLAMP (curve->x1, 0, display->image->width - 1);
 
1378
  ys = CLAMP (curve->y1, 0, display->image->height - 1);
 
1379
  xe = CLAMP (curve->x2, 0, display->image->width - 1);
 
1380
  ye = CLAMP (curve->y2, 0, display->image->height - 1);
1359
1381
  x1 = MIN (xs, xe);
1360
1382
  y1 = MIN (ys, ye);
1361
1383
  x2 = MAX (xs, xe) + 1;  /*  +1 because if xe = 199 & xs = 0, x2 - x1, width = 200  */
1372
1394
  eheight = (y2 - y1) * EXTEND_BY + FIXED;
1373
1395
 
1374
1396
  if (xe >= xs)
1375
 
    x2 += CLAMP (ewidth, 0, gdisp->gimage->width - x2);
 
1397
    x2 += CLAMP (ewidth, 0, display->image->width - x2);
1376
1398
  else
1377
1399
    x1 -= CLAMP (ewidth, 0, x1);
1378
1400
  if (ye >= ys)
1379
 
    y2 += CLAMP (eheight, 0, gdisp->gimage->height - y2);
 
1401
    y2 += CLAMP (eheight, 0, display->image->height - y2);
1380
1402
  else
1381
1403
    y1 -= CLAMP (eheight, 0, y1);
1382
1404
 
1396
1418
      /* Initialise the gradient map tile manager for this image if we
1397
1419
       * don't already have one. */
1398
1420
      if (!iscissors->gradient_map)
1399
 
          iscissors->gradient_map = gradient_map_new (gdisp->gimage);
 
1421
          iscissors->gradient_map = gradient_map_new (display->image);
1400
1422
 
1401
1423
      /*  allocate the dynamic programming array  */
1402
1424
      iscissors->dp_buf =
1403
 
        temp_buf_resize (iscissors->dp_buf, 4, x1, y1, width, height);
 
1425
        temp_buf_resize (iscissors->dp_buf, 4, x1, y1, width, height);
1404
1426
 
1405
1427
      /*  find the optimal path of pixels from (x1, y1) to (x2, y2)  */
1406
1428
      find_optimal_path (iscissors->gradient_map, iscissors->dp_buf,
1407
 
                         x1, y1, x2, y2, xs, ys);
 
1429
                         x1, y1, x2, y2, xs, ys);
1408
1430
 
1409
1431
      /*  get a list of the pixels in the optimal path  */
1410
1432
      curve->points = plot_pixels (iscissors, iscissors->dp_buf,
1411
 
                                   x1, y1, xs, ys, xe, ye);
 
1433
                                   x1, y1, xs, ys, xe, ye);
1412
1434
    }
1413
1435
  /*  If the bounding box has no width  */
1414
1436
  else if ((x2 - x1) == 0)
1418
1440
      dir = (ys > ye) ? -1 : 1;
1419
1441
      curve->points = g_ptr_array_new ();
1420
1442
      while (y != ye)
1421
 
        {
1422
 
          g_ptr_array_add (curve->points, GINT_TO_POINTER ((y << 16) + xs));
1423
 
          y += dir;
1424
 
        }
 
1443
        {
 
1444
          g_ptr_array_add (curve->points, GINT_TO_POINTER ((y << 16) + xs));
 
1445
          y += dir;
 
1446
        }
1425
1447
    }
1426
1448
  /*  If the bounding box has no height  */
1427
1449
  else if ((y2 - y1) == 0)
1431
1453
      dir = (xs > xe) ? -1 : 1;
1432
1454
      curve->points = g_ptr_array_new ();
1433
1455
      while (x != xe)
1434
 
        {
1435
 
          g_ptr_array_add (curve->points, GINT_TO_POINTER ((ys << 16) + x));
1436
 
          x += dir;
1437
 
        }
 
1456
        {
 
1457
          g_ptr_array_add (curve->points, GINT_TO_POINTER ((ys << 16) + x));
 
1458
          x += dir;
 
1459
        }
1438
1460
    }
1439
1461
}
1440
1462
 
1442
1464
/* badly need to get a replacement - this is _way_ too expensive */
1443
1465
static gboolean
1444
1466
gradient_map_value (TileManager *map,
1445
 
                    gint         x,
1446
 
                    gint         y,
1447
 
                    guint8      *grad,
1448
 
                    guint8      *dir)
 
1467
                    gint         x,
 
1468
                    gint         y,
 
1469
                    guint8      *grad,
 
1470
                    guint8      *dir)
1449
1471
{
1450
1472
  static gint  cur_tilex;
1451
1473
  static gint  cur_tiley;
1456
1478
      y / TILE_HEIGHT != cur_tiley)
1457
1479
    {
1458
1480
      if (cur_tile)
1459
 
        tile_release (cur_tile, FALSE);
 
1481
        tile_release (cur_tile, FALSE);
1460
1482
      cur_tile = tile_manager_get_tile (map, x, y, TRUE, FALSE);
1461
1483
      if (!cur_tile)
1462
 
        return FALSE;
 
1484
        return FALSE;
1463
1485
      cur_tilex = x / TILE_WIDTH;
1464
1486
      cur_tiley = y / TILE_HEIGHT;
1465
1487
    }
1473
1495
 
1474
1496
static gint
1475
1497
calculate_link (TileManager *gradient_map,
1476
 
                gint         x,
1477
 
                gint         y,
1478
 
                guint32      pixel,
1479
 
                gint         link)
 
1498
                gint         x,
 
1499
                gint         y,
 
1500
                guint32      pixel,
 
1501
                gint         link)
1480
1502
{
1481
1503
  gint   value = 0;
1482
1504
  guint8 grad1, dir1, grad2, dir2;
1500
1522
  /*  calculate the contribution of the gradient direction  */
1501
1523
  x += (gint8)(pixel & 0xff);
1502
1524
  y += (gint8)((pixel & 0xff00) >> 8);
 
1525
 
1503
1526
  if (!gradient_map_value (gradient_map, x, y, &grad2, &dir2))
1504
1527
    {
1505
1528
      grad2 = 0;
1506
1529
      dir2 = 255;
1507
1530
    }
1508
 
  value += (direction_value[dir1][link] + direction_value[dir2][link]) *
1509
 
    OMEGA_D;
 
1531
 
 
1532
  value +=
 
1533
    (direction_value[dir1][link] + direction_value[dir2][link]) * OMEGA_D;
1510
1534
 
1511
1535
  return value;
1512
1536
}
1514
1538
 
1515
1539
static GPtrArray *
1516
1540
plot_pixels (GimpIscissorsTool *iscissors,
1517
 
             TempBuf           *dp_buf,
1518
 
             gint               x1,
1519
 
             gint               y1,
1520
 
             gint               xs,
1521
 
             gint               ys,
1522
 
             gint               xe,
1523
 
             gint               ye)
 
1541
             TempBuf           *dp_buf,
 
1542
             gint               x1,
 
1543
             gint               y1,
 
1544
             gint               xs,
 
1545
             gint               ys,
 
1546
             gint               xe,
 
1547
             gint               ye)
1524
1548
{
1525
1549
  gint       x, y;
1526
1550
  guint32    coords;
1539
1563
 
1540
1564
  list = g_ptr_array_new ();
1541
1565
 
1542
 
  while (1)
 
1566
  while (TRUE)
1543
1567
    {
1544
1568
      coords = (y << 16) + x;
1545
1569
      g_ptr_array_add (list, GINT_TO_POINTER (coords));
1546
1570
 
1547
1571
      link = PIXEL_DIR (*data);
1548
1572
      if (link == SEED_POINT)
1549
 
        return list;
 
1573
        return list;
1550
1574
 
1551
1575
      x += move[link][0];
1552
1576
      y += move[link][1];
1565
1589
 
1566
1590
static void
1567
1591
find_optimal_path (TileManager *gradient_map,
1568
 
                   TempBuf     *dp_buf,
1569
 
                   gint         x1,
1570
 
                   gint         y1,
1571
 
                   gint         x2,
1572
 
                   gint         y2,
1573
 
                   gint         xs,
1574
 
                   gint         ys)
 
1592
                   TempBuf     *dp_buf,
 
1593
                   gint         x1,
 
1594
                   gint         y1,
 
1595
                   gint         x2,
 
1596
                   gint         y2,
 
1597
                   gint         xs,
 
1598
                   gint         ys)
1575
1599
{
1576
1600
  gint     i, j, k;
1577
1601
  gint     x, y;
1605
1629
      d = data + (y-y1) * dp_buf->width + (x-x1);
1606
1630
 
1607
1631
      for (j = 0; j < dp_buf->width; j++)
1608
 
        {
1609
 
          min_cost = G_MAXINT;
1610
 
 
1611
 
          /* pixel[] array encodes how to get to a neigbour, if possible.
1612
 
           * 0 means no connection (eg edge).
1613
 
           * Rest packed as bottom two bytes: y offset then x offset.
1614
 
           * Initially, we assume we can't get anywhere. */
1615
 
          for (k = 0; k < 8; k++)
1616
 
            pixel[k] = 0;
1617
 
 
1618
 
          /*  Find the valid neighboring pixels  */
1619
 
          /*  the previous pixel  */
1620
 
          if (j)
1621
 
            pixel[((dirx == 1) ? 4 : 0)] = PACK (-dirx, 0);
1622
 
 
1623
 
          /*  the previous row of pixels  */
1624
 
          if (i)
1625
 
            {
1626
 
              pixel[((diry == 1) ? 5 : 1)] = PACK (0, -diry);
1627
 
 
1628
 
              link = (linkdir == 1) ? 3 : 2;
1629
 
              if (j)
1630
 
                pixel[((diry == 1) ? (link + 4) : link)] = PACK(-dirx, -diry);
1631
 
 
1632
 
              link = (linkdir == 1) ? 2 : 3;
1633
 
              if (j != dp_buf->width - 1)
1634
 
                pixel[((diry == 1) ? (link + 4) : link)] = PACK (dirx, -diry);
1635
 
            }
1636
 
 
1637
 
          /*  find the minimum cost of going through each neighbor to reach the
1638
 
           *  seed point...
1639
 
           */
1640
 
          link = -1;
1641
 
          for (k = 0; k < 8; k ++)
1642
 
            if (pixel[k])
1643
 
              {
1644
 
                link_cost[k] = calculate_link (gradient_map,
 
1632
        {
 
1633
          min_cost = G_MAXINT;
 
1634
 
 
1635
          /* pixel[] array encodes how to get to a neigbour, if possible.
 
1636
           * 0 means no connection (eg edge).
 
1637
           * Rest packed as bottom two bytes: y offset then x offset.
 
1638
           * Initially, we assume we can't get anywhere. */
 
1639
          for (k = 0; k < 8; k++)
 
1640
            pixel[k] = 0;
 
1641
 
 
1642
          /*  Find the valid neighboring pixels  */
 
1643
          /*  the previous pixel  */
 
1644
          if (j)
 
1645
            pixel[((dirx == 1) ? 4 : 0)] = PACK (-dirx, 0);
 
1646
 
 
1647
          /*  the previous row of pixels  */
 
1648
          if (i)
 
1649
            {
 
1650
              pixel[((diry == 1) ? 5 : 1)] = PACK (0, -diry);
 
1651
 
 
1652
              link = (linkdir == 1) ? 3 : 2;
 
1653
              if (j)
 
1654
                pixel[((diry == 1) ? (link + 4) : link)] = PACK(-dirx, -diry);
 
1655
 
 
1656
              link = (linkdir == 1) ? 2 : 3;
 
1657
              if (j != dp_buf->width - 1)
 
1658
                pixel[((diry == 1) ? (link + 4) : link)] = PACK (dirx, -diry);
 
1659
            }
 
1660
 
 
1661
          /*  find the minimum cost of going through each neighbor to reach the
 
1662
           *  seed point...
 
1663
           */
 
1664
          link = -1;
 
1665
          for (k = 0; k < 8; k ++)
 
1666
            if (pixel[k])
 
1667
              {
 
1668
                link_cost[k] = calculate_link (gradient_map,
1645
1669
                                               xs + j*dirx, ys + i*diry,
1646
1670
                                               pixel [k],
1647
1671
                                               ((k > 3) ? k - 4 : k));
1648
 
                offset = OFFSET (pixel [k]);
1649
 
                pixel_cost[k] = PIXEL_COST (d[offset]);
1650
 
                cum_cost[k] = pixel_cost[k] + link_cost[k];
1651
 
                if (cum_cost[k] < min_cost)
1652
 
                  {
1653
 
                    min_cost = cum_cost[k];
1654
 
                    link = k;
1655
 
                  }
1656
 
              }
1657
 
 
1658
 
          /*  If anything can be done...  */
1659
 
          if (link >= 0)
1660
 
            {
1661
 
              /*  set the cumulative cost of this pixel and the new direction  */
1662
 
              *d = (cum_cost[link] << 8) + link;
1663
 
 
1664
 
              /*  possibly change the links from the other pixels to this pixel...
1665
 
               *  these changes occur if a neighboring pixel will receive a lower
1666
 
               *  cumulative cost by going through this pixel.
1667
 
               */
1668
 
              for (k = 0; k < 8; k ++)
1669
 
                if (pixel[k] && k != link)
1670
 
                  {
1671
 
                    /*  if the cumulative cost at the neighbor is greater than
1672
 
                     *  the cost through the link to the current pixel, change the
1673
 
                     *  neighbor's link to point to the current pixel.
1674
 
                     */
1675
 
                    new_cost = link_cost[k] + cum_cost[link];
1676
 
                    if (pixel_cost[k] > new_cost)
1677
 
                    {
1678
 
                      /*  reverse the link direction   /-----------------------\ */
1679
 
                      offset = OFFSET (pixel[k]);
1680
 
                      d[offset] = (new_cost << 8) + ((k > 3) ? k - 4 : k + 4);
1681
 
                    }
1682
 
                  }
1683
 
            }
1684
 
          /*  Set the seed point  */
1685
 
          else if (!i && !j)
1686
 
            *d = SEED_POINT;
1687
 
 
1688
 
          /*  increment the data pointer and the x counter  */
1689
 
          d += dirx;
1690
 
          x += dirx;
1691
 
        }
 
1672
                offset = OFFSET (pixel [k]);
 
1673
                pixel_cost[k] = PIXEL_COST (d[offset]);
 
1674
                cum_cost[k] = pixel_cost[k] + link_cost[k];
 
1675
                if (cum_cost[k] < min_cost)
 
1676
                  {
 
1677
                    min_cost = cum_cost[k];
 
1678
                    link = k;
 
1679
                  }
 
1680
              }
 
1681
 
 
1682
          /*  If anything can be done...  */
 
1683
          if (link >= 0)
 
1684
            {
 
1685
              /*  set the cumulative cost of this pixel and the new direction  */
 
1686
              *d = (cum_cost[link] << 8) + link;
 
1687
 
 
1688
              /*  possibly change the links from the other pixels to this pixel...
 
1689
               *  these changes occur if a neighboring pixel will receive a lower
 
1690
               *  cumulative cost by going through this pixel.
 
1691
               */
 
1692
              for (k = 0; k < 8; k ++)
 
1693
                if (pixel[k] && k != link)
 
1694
                  {
 
1695
                    /*  if the cumulative cost at the neighbor is greater than
 
1696
                     *  the cost through the link to the current pixel, change the
 
1697
                     *  neighbor's link to point to the current pixel.
 
1698
                     */
 
1699
                    new_cost = link_cost[k] + cum_cost[link];
 
1700
                    if (pixel_cost[k] > new_cost)
 
1701
                    {
 
1702
                      /*  reverse the link direction   /-----------------------\ */
 
1703
                      offset = OFFSET (pixel[k]);
 
1704
                      d[offset] = (new_cost << 8) + ((k > 3) ? k - 4 : k + 4);
 
1705
                    }
 
1706
                  }
 
1707
            }
 
1708
          /*  Set the seed point  */
 
1709
          else if (!i && !j)
 
1710
            *d = SEED_POINT;
 
1711
 
 
1712
          /*  increment the data pointer and the x counter  */
 
1713
          d += dirx;
 
1714
          x += dirx;
 
1715
        }
1692
1716
 
1693
1717
      /*  increment the y counter  */
1694
1718
      y += diry;
1699
1723
/* Called to fill in a newly referenced tile in the gradient map */
1700
1724
static void
1701
1725
gradmap_tile_validate (TileManager *tm,
1702
 
                       Tile        *tile)
 
1726
                       Tile        *tile)
1703
1727
{
1704
1728
  static gboolean first_gradient = TRUE;
1705
1729
 
1706
 
  gint         x, y;
1707
 
  gint         dw, dh;
1708
 
  gint         sw, sh;
1709
 
  gint         i, j;
1710
 
  gint         b;
1711
 
  gfloat       gradient;
1712
 
  guint8      *gradmap;
1713
 
  guint8      *tiledata;
1714
 
  guint8      *datah, *datav;
1715
 
  gint8        hmax, vmax;
1716
 
  Tile        *srctile;
1717
 
  PixelRegion  srcPR, destPR;
1718
 
  GimpImage   *gimage;
1719
 
 
1720
 
  gimage = (GimpImage *) tile_manager_get_user_data (tm);
 
1730
  GimpImage    *image = tile_manager_get_user_data (tm);
 
1731
  GimpPickable *pickable;
 
1732
  Tile         *srctile;
 
1733
  PixelRegion   srcPR, destPR;
 
1734
  gint          x, y;
 
1735
  gint          dw, dh;
 
1736
  gint          sw, sh;
 
1737
  gint          i, j;
 
1738
  gint          b;
 
1739
  gfloat        gradient;
 
1740
  guint8       *gradmap;
 
1741
  guint8       *tiledata;
 
1742
  guint8       *datah, *datav;
 
1743
  gint8         hmax, vmax;
1721
1744
 
1722
1745
  if (first_gradient)
1723
1746
    {
1725
1748
 
1726
1749
      /*  compute the distance weights  */
1727
1750
      for (i = 0; i < GRADIENT_SEARCH; i++)
1728
 
        for (j = 0; j < GRADIENT_SEARCH; j++)
1729
 
          distance_weights[i * GRADIENT_SEARCH + j] =
1730
 
            1.0 / (1 + sqrt (SQR(i - radius) + SQR(j - radius)));
 
1751
        for (j = 0; j < GRADIENT_SEARCH; j++)
 
1752
          distance_weights[i * GRADIENT_SEARCH + j] =
 
1753
            1.0 / (1 + sqrt (SQR(i - radius) + SQR(j - radius)));
1731
1754
 
1732
1755
      first_gradient = FALSE;
1733
1756
    }
1736
1759
  dw = tile_ewidth (tile);
1737
1760
  dh = tile_eheight (tile);
1738
1761
 
1739
 
  gimp_projection_finish_draw (gimage->projection);
1740
 
  gimp_projection_flush_now (gimage->projection);
1741
 
 
1742
 
  /* get corresponding tile in the gimage */
1743
 
  srctile = tile_manager_get_tile (gimp_projection_get_tiles (gimage->projection),
1744
 
                                   x, y, TRUE, FALSE);
 
1762
  pickable = GIMP_PICKABLE (image->projection);
 
1763
 
 
1764
  gimp_pickable_flush (pickable);
 
1765
 
 
1766
  /* get corresponding tile in the image */
 
1767
  srctile = tile_manager_get_tile (gimp_pickable_get_tiles (pickable),
 
1768
                                   x, y, TRUE, FALSE);
1745
1769
  if (!srctile)
1746
1770
    return;
1747
1771
 
1748
1772
  sw = tile_ewidth (srctile);
1749
1773
  sh = tile_eheight (srctile);
1750
1774
 
1751
 
  srcPR.w         = MIN (dw, sw);
1752
 
  srcPR.h         = MIN (dh, sh);
1753
 
  srcPR.bytes     = gimp_projection_get_bytes (gimage->projection);
1754
 
  srcPR.data      = tile_data_pointer (srctile, 0, 0);
1755
 
  srcPR.rowstride = srcPR.w * srcPR.bytes;
 
1775
  pixel_region_init_data (&srcPR, tile_data_pointer (srctile, 0, 0),
 
1776
                          gimp_pickable_get_bytes (pickable),
 
1777
                          gimp_pickable_get_bytes (pickable) *
 
1778
                          MIN (dw, sw),
 
1779
                          0, 0, MIN (dw, sw), MIN (dh, sh));
1756
1780
 
1757
1781
  /* XXX tile edges? */
1758
1782
 
1784
1808
      gradmap = tiledata + tile_ewidth (tile) * COST_WIDTH * i;
1785
1809
 
1786
1810
      for (j = 0; j < srcPR.w; j++)
1787
 
        {
1788
 
          hmax = datah[0] - 128;
1789
 
          vmax = datav[0] - 128;
1790
 
          for (b = 1; b < srcPR.bytes; b++)
1791
 
            {
1792
 
              if (abs (datah[b] - 128) > abs (hmax)) hmax = datah[b] - 128;
1793
 
              if (abs (datav[b] - 128) > abs (vmax)) vmax = datav[b] - 128;
1794
 
            }
1795
 
 
1796
 
          if (i == 0 || j == 0 || i == srcPR.h-1 || j == srcPR.w-1)
1797
 
          {
1798
 
              gradmap[j*COST_WIDTH] = 0;
1799
 
              gradmap[j*COST_WIDTH + 1] = 255;
1800
 
              goto contin;
1801
 
          }
1802
 
 
1803
 
          /* 1 byte absolute magitude first */
1804
 
          gradient = sqrt(SQR(hmax) + SQR(vmax));
1805
 
          gradmap[j*COST_WIDTH] = gradient * 255 / MAX_GRADIENT;
1806
 
 
1807
 
          /* then 1 byte direction */
1808
 
          if (gradient > MIN_GRADIENT)
1809
 
            {
1810
 
              gfloat direction;
1811
 
 
1812
 
              if (!hmax)
1813
 
                direction = (vmax > 0) ? G_PI_2 : -G_PI_2;
1814
 
              else
1815
 
                direction = atan ((double) vmax / (double) hmax);
1816
 
 
1817
 
              /* Scale the direction from between 0 and 254,
1818
 
               *  corresponding to -PI/2, PI/2 255 is reserved for
1819
 
               *  directionless pixels */
1820
 
              gradmap[j*COST_WIDTH + 1] =
1821
 
                (guint8) (254 * (direction + G_PI_2) / G_PI);
1822
 
            }
1823
 
          else
1824
 
            gradmap[j*COST_WIDTH + 1] = 255; /* reserved for weak gradient */
1825
 
 
1826
 
contin:
1827
 
          datah += srcPR.bytes;
1828
 
          datav += srcPR.bytes;
1829
 
        }
 
1811
        {
 
1812
          hmax = datah[0] - 128;
 
1813
          vmax = datav[0] - 128;
 
1814
          for (b = 1; b < srcPR.bytes; b++)
 
1815
            {
 
1816
              if (abs (datah[b] - 128) > abs (hmax)) hmax = datah[b] - 128;
 
1817
              if (abs (datav[b] - 128) > abs (vmax)) vmax = datav[b] - 128;
 
1818
            }
 
1819
 
 
1820
          if (i == 0 || j == 0 || i == srcPR.h-1 || j == srcPR.w-1)
 
1821
          {
 
1822
              gradmap[j*COST_WIDTH] = 0;
 
1823
              gradmap[j*COST_WIDTH + 1] = 255;
 
1824
              goto contin;
 
1825
          }
 
1826
 
 
1827
          /* 1 byte absolute magitude first */
 
1828
          gradient = sqrt(SQR(hmax) + SQR(vmax));
 
1829
          gradmap[j*COST_WIDTH] = gradient * 255 / MAX_GRADIENT;
 
1830
 
 
1831
          /* then 1 byte direction */
 
1832
          if (gradient > MIN_GRADIENT)
 
1833
            {
 
1834
              gfloat direction;
 
1835
 
 
1836
              if (!hmax)
 
1837
                direction = (vmax > 0) ? G_PI_2 : -G_PI_2;
 
1838
              else
 
1839
                direction = atan ((double) vmax / (double) hmax);
 
1840
 
 
1841
              /* Scale the direction from between 0 and 254,
 
1842
               *  corresponding to -PI/2, PI/2 255 is reserved for
 
1843
               *  directionless pixels */
 
1844
              gradmap[j*COST_WIDTH + 1] =
 
1845
                (guint8) (254 * (direction + G_PI_2) / G_PI);
 
1846
            }
 
1847
          else
 
1848
            gradmap[j*COST_WIDTH + 1] = 255; /* reserved for weak gradient */
 
1849
 
 
1850
        contin:
 
1851
          datah += srcPR.bytes;
 
1852
          datav += srcPR.bytes;
 
1853
        }
1830
1854
    }
1831
1855
 
1832
1856
  tile_release (srctile, FALSE);
1833
1857
}
1834
1858
 
1835
1859
static TileManager *
1836
 
gradient_map_new (GimpImage *gimage)
 
1860
gradient_map_new (GimpImage *image)
1837
1861
{
1838
1862
  TileManager *tm;
1839
1863
 
1840
 
  tm = tile_manager_new (gimage->width, gimage->height,
1841
 
                         sizeof (guint8) * COST_WIDTH);
1842
 
  tile_manager_set_user_data (tm, gimage);
 
1864
  tm = tile_manager_new (image->width, image->height,
 
1865
                         sizeof (guint8) * COST_WIDTH);
 
1866
  tile_manager_set_user_data (tm, image);
1843
1867
  tile_manager_set_validate_proc (tm, gradmap_tile_validate);
1844
1868
 
1845
1869
  return tm;
1847
1871
 
1848
1872
static void
1849
1873
find_max_gradient (GimpIscissorsTool *iscissors,
1850
 
                   GimpImage         *gimage,
1851
 
                   gint              *x,
1852
 
                   gint              *y)
 
1874
                   GimpImage         *image,
 
1875
                   gint              *x,
 
1876
                   gint              *y)
1853
1877
{
1854
1878
  PixelRegion  srcPR;
1855
1879
  gint         radius;
1864
1888
  /* Initialise the gradient map tile manager for this image if we
1865
1889
   * don't already have one. */
1866
1890
  if (!iscissors->gradient_map)
1867
 
    iscissors->gradient_map = gradient_map_new (gimage);
 
1891
    iscissors->gradient_map = gradient_map_new (image);
1868
1892
 
1869
1893
  radius = GRADIENT_SEARCH >> 1;
1870
1894
 
1871
1895
  /*  calculate the extent of the search  */
1872
 
  cx = CLAMP (*x, 0, gimage->width);
1873
 
  cy = CLAMP (*y, 0, gimage->height);
 
1896
  cx = CLAMP (*x, 0, image->width);
 
1897
  cy = CLAMP (*y, 0, image->height);
1874
1898
  sx = cx - radius;
1875
1899
  sy = cy - radius;
1876
 
  x1 = CLAMP (cx - radius, 0, gimage->width);
1877
 
  y1 = CLAMP (cy - radius, 0, gimage->height);
1878
 
  x2 = CLAMP (cx + radius, 0, gimage->width);
1879
 
  y2 = CLAMP (cy + radius, 0, gimage->height);
 
1900
  x1 = CLAMP (cx - radius, 0, image->width);
 
1901
  y1 = CLAMP (cy - radius, 0, image->height);
 
1902
  x2 = CLAMP (cx + radius, 0, image->width);
 
1903
  y2 = CLAMP (cy + radius, 0, image->height);
1880
1904
  /*  calculate the factor to multiply the distance from the cursor by  */
1881
1905
 
1882
1906
  max_gradient = 0;
1885
1909
 
1886
1910
  /*  Find the point of max gradient  */
1887
1911
  pixel_region_init (&srcPR, iscissors->gradient_map,
1888
 
                     x1, y1, x2 - x1, y2 - y1, FALSE);
 
1912
                     x1, y1, x2 - x1, y2 - y1, FALSE);
1889
1913
 
1890
1914
  /* this iterates over 1, 2 or 4 tiles only */
1891
1915
  for (pr = pixel_regions_register (1, &srcPR);
1895
1919
      endx = srcPR.x + srcPR.w;
1896
1920
      endy = srcPR.y + srcPR.h;
1897
1921
      for (i = srcPR.y; i < endy; i++)
1898
 
        {
1899
 
          gradient = srcPR.data + srcPR.rowstride * (i - srcPR.y);
1900
 
          for (j = srcPR.x; j < endx; j++)
1901
 
            {
1902
 
              g = *gradient;
1903
 
              gradient += COST_WIDTH;
1904
 
              g *= distance_weights [(i-y1) * GRADIENT_SEARCH + (j-x1)];
1905
 
              if (g > max_gradient)
1906
 
                {
1907
 
                  max_gradient = g;
1908
 
                  *x = j;
1909
 
                  *y = i;
1910
 
                }
1911
 
            }
1912
 
        }
 
1922
        {
 
1923
          gradient = srcPR.data + srcPR.rowstride * (i - srcPR.y);
 
1924
          for (j = srcPR.x; j < endx; j++)
 
1925
            {
 
1926
              g = *gradient;
 
1927
              gradient += COST_WIDTH;
 
1928
              g *= distance_weights [(i-y1) * GRADIENT_SEARCH + (j-x1)];
 
1929
              if (g > max_gradient)
 
1930
                {
 
1931
                  max_gradient = g;
 
1932
                  *x = j;
 
1933
                  *y = i;
 
1934
                }
 
1935
            }
 
1936
        }
1913
1937
    }
1914
1938
}