gimpvectortool.c 60.6 KB
Newer Older
1
2
3
4
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * Vector tool
5
 * Copyright (C) 2003 Simon Budig  <simon@gimp.org>
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "config.h"

#include <gtk/gtk.h>
25
#include <gdk/gdkkeysyms.h>
26
27
28
29
30

#include "libgimpmath/gimpmath.h"
#include "libgimpbase/gimpbase.h"
#include "libgimpwidgets/gimpwidgets.h"

31
#include "tools-types.h"
32

33
34
#include "core/gimp.h"
#include "core/gimpcontext.h"
35
#include "core/gimpchannel-select.h"
36
#include "core/gimpimage.h"
37
#include "core/gimpimage-undo-push.h"
38
#include "core/gimplist.h"
39
#include "core/gimptoolinfo.h"
40
41
#include "core/gimpundo.h"
#include "core/gimpundostack.h"
42
43
44

#include "vectors/gimpanchor.h"
#include "vectors/gimpvectors.h"
45
#include "vectors/gimpbezierstroke.h"
46

47
48
#include "widgets/gimphelp-ids.h"

49
#include "display/gimpdisplay.h"
50
51
#include "display/gimpdisplayshell.h"
#include "display/gimpdisplayshell-scale.h"
52

53
#include "gimptoolcontrol.h"
54
#include "gimpvectoroptions.h"
55
56
#include "gimpvectortool.h"

57
#include "dialogs/stroke-dialog.h"
58

59
#include "gimp-intl.h"
60
61


62
#define TARGET 9
63

64
65
66
67
#define TOGGLE_MASK GDK_SHIFT_MASK
#define MOVE_MASK   GDK_MOD1_MASK
#define INSDEL_MASK GDK_CONTROL_MASK

68
69

/*  local function prototypes  */
70

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
static void     gimp_vector_tool_class_init      (GimpVectorToolClass *klass);
static void     gimp_vector_tool_init            (GimpVectorTool      *tool);

static void     gimp_vector_tool_control         (GimpTool        *tool,
                                                  GimpToolAction   action,
                                                  GimpDisplay     *gdisp);
static void     gimp_vector_tool_button_press    (GimpTool        *tool,
                                                  GimpCoords      *coords,
                                                  guint32          time,
                                                  GdkModifierType  state,
                                                  GimpDisplay     *gdisp);
static void     gimp_vector_tool_button_release  (GimpTool        *tool,
                                                  GimpCoords      *coords,
                                                  guint32          time,
                                                  GdkModifierType  state,
                                                  GimpDisplay     *gdisp);
static void     gimp_vector_tool_motion          (GimpTool        *tool,
                                                  GimpCoords      *coords,
                                                  guint32          time,
                                                  GdkModifierType  state,
                                                  GimpDisplay     *gdisp);
static gboolean gimp_vector_tool_key_press       (GimpTool        *tool,
                                                  GdkEventKey     *kevent,
                                                  GimpDisplay     *gdisp);
static void     gimp_vector_tool_modifier_key    (GimpTool        *tool,
                                                  GdkModifierType  key,
                                                  gboolean         press,
                                                  GdkModifierType  state,
                                                  GimpDisplay     *gdisp);
static void     gimp_vector_tool_oper_update     (GimpTool        *tool,
                                                  GimpCoords      *coords,
                                                  GdkModifierType  state,
                                                  GimpDisplay     *gdisp);
static void     gimp_vector_tool_status_update   (GimpTool        *tool,
                                                  GimpDisplay     *gdisp);
static void     gimp_vector_tool_cursor_update   (GimpTool        *tool,
                                                  GimpCoords      *coords,
                                                  GdkModifierType  state,
                                                  GimpDisplay     *gdisp);

static void     gimp_vector_tool_draw            (GimpDrawTool    *draw_tool);

static void     gimp_vector_tool_vectors_changed (GimpImage       *gimage,
                                                  GimpVectorTool  *vector_tool);
static void     gimp_vector_tool_vectors_removed (GimpVectors     *vectors,
                                                  GimpVectorTool  *vector_tool);
static void     gimp_vector_tool_vectors_visible (GimpVectors     *vectors,
                                                  GimpVectorTool  *vector_tool);
static void     gimp_vector_tool_vectors_freeze  (GimpVectors     *vectors,
                                                  GimpVectorTool  *vector_tool);
static void     gimp_vector_tool_vectors_thaw    (GimpVectors     *vectors,
                                                  GimpVectorTool  *vector_tool);

static void     gimp_vector_tool_move_selected_anchors
                                                 (GimpVectorTool  *vector_tool,
                                                  gdouble          x,
                                                  gdouble          y);
static void     gimp_vector_tool_delete_selected_anchors
                                                 (GimpVectorTool  *vector_tool);
static void     gimp_vector_tool_verify_state    (GimpVectorTool  *vector_tool);
static void     gimp_vector_tool_undo_push       (GimpVectorTool  *vector_tool,
                                                  const gchar     *desc);

static void     gimp_vector_tool_to_selection    (GimpVectorTool  *vector_tool);
static void     gimp_vector_tool_to_selection_extended
                                                 (GimpVectorTool  *vector_tool,
                                                  gint             state);
static void     gimp_vector_tool_stroke_vectors  (GimpVectorTool  *vector_tool,
                                                  GtkWidget       *button);
140

141

142
static GimpDrawToolClass *parent_class = NULL;
143
144
145


void
146
147
gimp_vector_tool_register (GimpToolRegisterCallback callback,
                           gpointer                 data)
148
{
Nate Summers's avatar
Nate Summers committed
149
  (* callback) (GIMP_TYPE_VECTOR_TOOL,
150
151
                GIMP_TYPE_VECTOR_OPTIONS,
                gimp_vector_options_gui,
152
                0,
153
                "gimp-vector-tool",
154
155
                _("Paths"),
                _("Create and edit paths"),
156
                N_("_Paths"), "b",
157
                NULL, GIMP_HELP_TOOL_PATH,
Nate Summers's avatar
Nate Summers committed
158
                GIMP_STOCK_TOOL_PATH,
159
                data);
160
161
162
163
164
165
166
167
168
169
170
171
}

GType
gimp_vector_tool_get_type (void)
{
  static GType tool_type = 0;

  if (! tool_type)
    {
      static const GTypeInfo tool_info =
      {
        sizeof (GimpVectorToolClass),
172
173
174
175
176
177
178
179
        (GBaseInitFunc) NULL,
        (GBaseFinalizeFunc) NULL,
        (GClassInitFunc) gimp_vector_tool_class_init,
        NULL,           /* class_finalize */
        NULL,           /* class_data     */
        sizeof (GimpVectorTool),
        0,              /* n_preallocs    */
        (GInstanceInitFunc) gimp_vector_tool_init,
180
181
      };

182
      tool_type = g_type_register_static (GIMP_TYPE_DRAW_TOOL,
183
                                          "GimpVectorTool",
184
185
186
187
188
189
190
191
192
                                          &tool_info, 0);
    }

  return tool_type;
}

static void
gimp_vector_tool_class_init (GimpVectorToolClass *klass)
{
193
  GObjectClass      *object_class;
194
195
196
  GimpToolClass     *tool_class;
  GimpDrawToolClass *draw_tool_class;

197
  object_class    = G_OBJECT_CLASS (klass);
198
199
200
201
202
203
204
205
206
  tool_class      = GIMP_TOOL_CLASS (klass);
  draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass);

  parent_class = g_type_class_peek_parent (klass);

  tool_class->control        = gimp_vector_tool_control;
  tool_class->button_press   = gimp_vector_tool_button_press;
  tool_class->button_release = gimp_vector_tool_button_release;
  tool_class->motion         = gimp_vector_tool_motion;
207
  tool_class->key_press      = gimp_vector_tool_key_press;
208
  tool_class->modifier_key   = gimp_vector_tool_modifier_key;
209
  tool_class->oper_update    = gimp_vector_tool_oper_update;
210
211
212
213
214
215
216
217
  tool_class->cursor_update  = gimp_vector_tool_cursor_update;

  draw_tool_class->draw      = gimp_vector_tool_draw;
}

static void
gimp_vector_tool_init (GimpVectorTool *vector_tool)
{
218
  GimpTool *tool = GIMP_TOOL (vector_tool);
219

220
221
222
223
224
225
  gimp_tool_control_set_scroll_lock         (tool->control, TRUE);
  gimp_tool_control_set_handles_empty_image (tool->control, TRUE);
  gimp_tool_control_set_motion_mode         (tool->control,
                                             GIMP_MOTION_MODE_COMPRESS);
  gimp_tool_control_set_tool_cursor         (tool->control,
                                             GIMP_TOOL_CURSOR_PATHS);
226

227
  vector_tool->function       = VECTORS_CREATE_VECTOR;
228
  vector_tool->restriction    = GIMP_ANCHOR_FEATURE_NONE;
229
230
231
  vector_tool->modifier_lock  = FALSE;
  vector_tool->last_x         = 0.0;
  vector_tool->last_y         = 0.0;
232
  vector_tool->undo_motion    = FALSE;
233
  vector_tool->have_undo      = FALSE;
234
235

  vector_tool->cur_anchor     = NULL;
236
  vector_tool->cur_anchor2    = NULL;
237
  vector_tool->cur_stroke     = NULL;
238
  vector_tool->cur_position   = 0.0;
239
  vector_tool->cur_vectors    = NULL;
240
  vector_tool->vectors        = NULL;
241
242
243
244

  vector_tool->sel_count      = 0;
  vector_tool->sel_anchor     = NULL;
  vector_tool->sel_stroke     = NULL;
245

246
  vector_tool->saved_mode     = GIMP_VECTOR_MODE_DESIGN;
247
248
}

249

250
251
static void
gimp_vector_tool_control (GimpTool       *tool,
252
253
                          GimpToolAction  action,
                          GimpDisplay    *gdisp)
254
{
255
  GimpVectorTool *vector_tool = GIMP_VECTOR_TOOL (tool);
256
257
258
259
260
261
262
263
264
265

  switch (action)
    {
    case PAUSE:
      break;

    case RESUME:
      break;

    case HALT:
266
      gimp_vector_tool_set_vectors (vector_tool, NULL);
267
      gimp_tool_pop_status (tool, gdisp);
268
269
270
271
272
273
274
275
276
277
278
      break;

    default:
      break;
    }

  GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
}

static void
gimp_vector_tool_button_press (GimpTool        *tool,
279
280
281
282
                               GimpCoords      *coords,
                               guint32          time,
                               GdkModifierType  state,
                               GimpDisplay     *gdisp)
283
{
284
  GimpDrawTool      *draw_tool;
285
286
  GimpVectorTool    *vector_tool;
  GimpVectorOptions *options;
287
  GimpVectors       *vectors;
288

289
  draw_tool   = GIMP_DRAW_TOOL (tool);
290
  vector_tool = GIMP_VECTOR_TOOL (tool);
291
  options     = GIMP_VECTOR_OPTIONS (tool->tool_info->tool_options);
292

293
294
295
296
  /* do nothing if we are an FINISHED state */
  if (vector_tool->function == VECTORS_FINISHED)
    return;

297
298
  g_return_if_fail (vector_tool->vectors  != NULL                  ||
                    vector_tool->function == VECTORS_SELECT_VECTOR ||
299
300
                    vector_tool->function == VECTORS_CREATE_VECTOR);

301
302
  vector_tool->undo_motion = FALSE;

303
  /* save the current modifier state */
304
305

  vector_tool->saved_state = state;
306

307
308
309
310
311
312
  gimp_draw_tool_pause (draw_tool);

  if (gimp_draw_tool_is_active (draw_tool) && draw_tool->gdisp != gdisp)
    {
      gimp_draw_tool_stop (draw_tool);
    }
313

Simon Budig's avatar
Simon Budig committed
314
  gimp_tool_control_activate (tool->control);
315
316
  tool->gdisp = gdisp;

317
318
319
320
  /* select a vectors object */

  if (vector_tool->function == VECTORS_SELECT_VECTOR)
    {
321
      if (gimp_draw_tool_on_vectors (draw_tool, gdisp, coords, TARGET, TARGET,
322
                                     NULL, NULL, NULL, NULL, NULL, &vectors))
323
        {
324
          gimp_vector_tool_set_vectors (vector_tool, vectors);
325
326
          gimp_image_set_active_vectors (gdisp->gimage, vectors);
        }
327
328
329
      vector_tool->function = VECTORS_FINISHED;
    }

330
331
332
333
  /* create a new vector from scratch */

  if (vector_tool->function == VECTORS_CREATE_VECTOR)
    {
334
335
      vectors = gimp_vectors_new (gdisp->gimage, _("Unnamed"));

336
337
338
      /* Undo step gets added implicitely */
      vector_tool->have_undo = TRUE;

339
340
      vector_tool->undo_motion = TRUE;

341
342
343
344
345
346
      gimp_image_add_vectors (gdisp->gimage, vectors, -1);
      gimp_image_flush (gdisp->gimage);

      gimp_vector_tool_set_vectors (vector_tool, vectors);

      vector_tool->function = VECTORS_CREATE_STROKE;
347

348
    }
349

350
351
  gimp_vectors_freeze (vector_tool->vectors);

352
  /* create a new stroke */
353

354
355
  if (vector_tool->function == VECTORS_CREATE_STROKE)
    {
356
      g_return_if_fail (vector_tool->vectors != NULL);
357

358
359
      gimp_vector_tool_undo_push (vector_tool, _("Add Stroke"));

360
361
      vector_tool->cur_stroke = gimp_bezier_stroke_new ();
      gimp_vectors_stroke_add (vector_tool->vectors, vector_tool->cur_stroke);
362

363
364
      vector_tool->undo_motion = TRUE;

365
      vector_tool->sel_stroke = vector_tool->cur_stroke;
366
      vector_tool->cur_anchor = NULL;
367
      vector_tool->sel_anchor = NULL;
368
      vector_tool->function = VECTORS_ADD_ANCHOR;
369
    }
370

371

372
  /* add an anchor to an existing stroke */
373

374
375
  if (vector_tool->function == VECTORS_ADD_ANCHOR)
    {
376
377
      gimp_vector_tool_undo_push (vector_tool, _("Add Anchor"));

378
379
      vector_tool->undo_motion = TRUE;

380
381
382
383
      vector_tool->cur_anchor =
                     gimp_bezier_stroke_extend (vector_tool->sel_stroke, coords,
                                                vector_tool->sel_anchor,
                                                EXTEND_EDITABLE);
384

385
386
      vector_tool->restriction = GIMP_ANCHOR_FEATURE_SYMMETRIC;

387
388
389
390
      if (!options->polygonal)
        vector_tool->function = VECTORS_MOVE_HANDLE;
      else
        vector_tool->function = VECTORS_MOVE_ANCHOR;
391
392
      vector_tool->cur_stroke = vector_tool->sel_stroke;
    }
393
394


395
  /* insertion of an anchor in a curve segment */
396
397

  if (vector_tool->function == VECTORS_INSERT_ANCHOR)
398
    {
399
400
      gimp_vector_tool_undo_push (vector_tool, _("Insert Anchor"));

401
402
      vector_tool->undo_motion = TRUE;

403
404
      vector_tool->cur_anchor =
                         gimp_stroke_anchor_insert (vector_tool->cur_stroke,
405
                                                    vector_tool->cur_anchor,
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
                                                    vector_tool->cur_position);
      if (vector_tool->cur_anchor)
        {
          if (options->polygonal)
            {
              gimp_stroke_anchor_convert (vector_tool->cur_stroke,
                                          vector_tool->cur_anchor,
                                          GIMP_ANCHOR_FEATURE_EDGE);
            }
          vector_tool->function = VECTORS_MOVE_ANCHOR;
        }
      else
        {
          vector_tool->function = VECTORS_FINISHED;
        }
421
    }
422

423

424
425
426
  /* move a handle */

  if (vector_tool->function == VECTORS_MOVE_HANDLE)
427
    {
428
429
      gimp_vector_tool_undo_push (vector_tool, _("Drag Handle"));

430
      if (vector_tool->cur_anchor->type == GIMP_ANCHOR_ANCHOR)
431
        {
432
433
434
435
436
437
438
439
          if (!vector_tool->cur_anchor->selected)
            {
              gimp_vectors_anchor_select (vector_tool->vectors,
                                          vector_tool->cur_stroke,
                                          vector_tool->cur_anchor,
                                          TRUE, TRUE);
              vector_tool->undo_motion = TRUE;
            }
440

441
442
443
          gimp_draw_tool_on_vectors_handle (GIMP_DRAW_TOOL (tool), gdisp,
                                            vector_tool->vectors, coords,
                                            TARGET, TARGET,
444
                                            GIMP_ANCHOR_CONTROL, TRUE,
445
446
                                            &vector_tool->cur_anchor,
                                            &vector_tool->cur_stroke);
447
448
          if (!vector_tool->cur_anchor)
            vector_tool->function = VECTORS_FINISHED;
449
        }
450
    }
451

452
453
454
455
456

  /* move an anchor */

  if (vector_tool->function == VECTORS_MOVE_ANCHOR)
    {
457
458
      gimp_vector_tool_undo_push (vector_tool, _("Drag Anchor"));

459
460
461
462
463
464
465
466
      if (!vector_tool->cur_anchor->selected)
        {
          gimp_vectors_anchor_select (vector_tool->vectors,
                                      vector_tool->cur_stroke,
                                      vector_tool->cur_anchor,
                                      TRUE, TRUE);
          vector_tool->undo_motion = TRUE;
        }
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
    }


  /* move multiple anchors */

  if (vector_tool->function == VECTORS_MOVE_ANCHORSET)
    {
      gimp_vector_tool_undo_push (vector_tool, _("Drag Anchors"));

      if (state & TOGGLE_MASK)
        {
          gimp_vectors_anchor_select (vector_tool->vectors,
                                      vector_tool->cur_stroke,
                                      vector_tool->cur_anchor,
                                      !vector_tool->cur_anchor->selected,
                                      FALSE);
483
          vector_tool->undo_motion = TRUE;
484
485
486
          if (vector_tool->cur_anchor->selected == FALSE)
            vector_tool->function = VECTORS_FINISHED;
        }
487
488
489
    }


490
491
492
493
494
495
496
497
498
  /* move a curve segment directly */

  if (vector_tool->function == VECTORS_MOVE_CURVE)
    {
      gimp_vector_tool_undo_push (vector_tool, _("Drag Curve"));

      /* the magic numbers are taken from the "feel good" parameter
       * from gimp_bezier_stroke_point_move_relative in gimpbezierstroke.c. */
      if (vector_tool->cur_position < 5.0 / 6.0)
499
500
501
502
503
504
        {
          gimp_vectors_anchor_select (vector_tool->vectors,
                                      vector_tool->cur_stroke,
                                      vector_tool->cur_anchor, TRUE, TRUE);
          vector_tool->undo_motion = TRUE;
        }
505

506
      if (vector_tool->cur_position > 1.0 / 6.0)
507
508
509
510
511
512
513
        {
          gimp_vectors_anchor_select (vector_tool->vectors,
                                      vector_tool->cur_stroke,
                                      vector_tool->cur_anchor2, TRUE,
                                      (vector_tool->cur_position >= 5.0 / 6.0));
          vector_tool->undo_motion = TRUE;
        }
514

515
516
517
    }


518
  /* connect two strokes */
519

520
521
  if (vector_tool->function == VECTORS_CONNECT_STROKES)
    {
522
523
      gimp_vector_tool_undo_push (vector_tool, _("Connect Strokes"));

524
525
526
527
      gimp_stroke_connect_stroke (vector_tool->sel_stroke,
                                  vector_tool->sel_anchor,
                                  vector_tool->cur_stroke,
                                  vector_tool->cur_anchor);
528
529
      vector_tool->undo_motion = TRUE;

530
531
      if (vector_tool->cur_stroke != vector_tool->sel_stroke &&
          gimp_stroke_is_empty (vector_tool->cur_stroke))
532
        {
533
534
          gimp_vectors_stroke_remove (vector_tool->vectors,
                                      vector_tool->cur_stroke);
535
        }
536
537
538
539
540
      vector_tool->sel_anchor = vector_tool->cur_anchor;
      vector_tool->cur_stroke = vector_tool->sel_stroke;

      gimp_vectors_anchor_select (vector_tool->vectors,
                                  vector_tool->sel_stroke,
541
                                  vector_tool->sel_anchor, TRUE, TRUE);
542

543
544
      vector_tool->function = VECTORS_FINISHED;
    }
545

546
547
548
549
550
551

  /* move a stroke or all strokes of a vectors object */

  if (vector_tool->function == VECTORS_MOVE_STROKE ||
      vector_tool->function == VECTORS_MOVE_VECTORS)
    {
552
553
      gimp_vector_tool_undo_push (vector_tool, _("Drag Path"));

554
555
556
557
      /* Work is being done in gimp_vector_tool_motion ()... */
    }


558
  /* convert an anchor to something that looks like an edge */
559

560
561
  if (vector_tool->function == VECTORS_CONVERT_EDGE)
    {
562
563
      gimp_vector_tool_undo_push (vector_tool, _("Convert Edge"));

564
565
566
      gimp_stroke_anchor_convert (vector_tool->cur_stroke,
                                  vector_tool->cur_anchor,
                                  GIMP_ANCHOR_FEATURE_EDGE);
567
      vector_tool->undo_motion = TRUE;
568

569
570
571
572
      if (vector_tool->cur_anchor->type == GIMP_ANCHOR_ANCHOR)
        {
          gimp_vectors_anchor_select (vector_tool->vectors,
                                      vector_tool->cur_stroke,
573
                                      vector_tool->cur_anchor, TRUE, TRUE);
574

575
          vector_tool->function = VECTORS_MOVE_ANCHOR;
576
        }
577
578
579
580
      else
        {
          vector_tool->cur_stroke = NULL;
          vector_tool->cur_anchor = NULL;
581

582
583
584
585
          /* avoid doing anything stupid */
          vector_tool->function = VECTORS_FINISHED;
        }
    }
Simon Budig's avatar
Simon Budig committed
586

587

588
589
590
  /* removal of a node in a stroke */

  if (vector_tool->function == VECTORS_DELETE_ANCHOR)
591
    {
592
593
      gimp_vector_tool_undo_push (vector_tool, _("Delete Anchor"));

594
595
      gimp_stroke_anchor_delete (vector_tool->cur_stroke,
                                 vector_tool->cur_anchor);
596
      vector_tool->undo_motion = TRUE;
597
598

      if (gimp_stroke_is_empty (vector_tool->cur_stroke))
599
        gimp_vectors_stroke_remove (vector_tool->vectors,
600
601
602
603
604
605
606
607
608
609
610
611
612
                                    vector_tool->cur_stroke);

      vector_tool->cur_stroke = NULL;
      vector_tool->cur_anchor = NULL;
      vector_tool->function = VECTORS_FINISHED;
    }


  /* deleting a segment (opening up a stroke) */

  if (vector_tool->function == VECTORS_DELETE_SEGMENT)
    {
      GimpStroke *new_stroke;
613
614
615

      gimp_vector_tool_undo_push (vector_tool, _("Delete Segment"));

616
617
618
619
620
      new_stroke = gimp_stroke_open (vector_tool->cur_stroke,
                                     vector_tool->cur_anchor);
      if (new_stroke)
        gimp_vectors_stroke_add (vector_tool->vectors, new_stroke);

621
      vector_tool->undo_motion = TRUE;
622
623
624
      vector_tool->cur_stroke = NULL;
      vector_tool->cur_anchor = NULL;
      vector_tool->function = VECTORS_FINISHED;
625
626
    }

627
628
629
  vector_tool->last_x = coords->x;
  vector_tool->last_y = coords->y;

630
631
  gimp_vectors_thaw (vector_tool->vectors);

632
  if (! gimp_draw_tool_is_active (draw_tool))
633
634
635
    {
      gimp_draw_tool_start (draw_tool, gdisp);
    }
636
637

  gimp_draw_tool_resume (draw_tool);
638
639
640
641
642
643
644
645
646
}

static void
gimp_vector_tool_button_release (GimpTool        *tool,
                                 GimpCoords      *coords,
                                 guint32          time,
                                 GdkModifierType  state,
                                 GimpDisplay     *gdisp)
{
647
  GimpVectorTool *vector_tool = GIMP_VECTOR_TOOL (tool);
648

649
  vector_tool->function = VECTORS_FINISHED;
650

651
652
  if (vector_tool->have_undo &&
      (! vector_tool->undo_motion || (state & GDK_BUTTON3_MASK)))
653
654
655
656
657
658
    {
      GimpUndo            *undo;
      GimpUndoAccumulator  accum = { 0, };

      undo = gimp_undo_stack_pop_undo (gdisp->gimage->undo_stack,
                                       GIMP_UNDO_MODE_UNDO, &accum);
659

660
      gimp_image_undo_event (gdisp->gimage, GIMP_UNDO_EVENT_UNDO_EXPIRED, undo);
661
662

      gimp_undo_free (undo, GIMP_UNDO_MODE_UNDO);
663
      g_object_unref (undo);
664
665
666
    }

  vector_tool->have_undo = FALSE;
667
  vector_tool->undo_motion = FALSE;
668

669
  gimp_tool_control_halt (tool->control);
670
  gimp_image_flush (gdisp->gimage);
671
672
673
674
675
676
677
678
679
}

static void
gimp_vector_tool_motion (GimpTool        *tool,
                         GimpCoords      *coords,
                         guint32          time,
                         GdkModifierType  state,
                         GimpDisplay     *gdisp)
{
680
681
682
  GimpVectorTool    *vector_tool;
  GimpVectorOptions *options;
  GimpAnchor        *anchor;
683
684

  vector_tool = GIMP_VECTOR_TOOL (tool);
685
  options     = GIMP_VECTOR_OPTIONS (tool->tool_info->tool_options);
686

687
688
689
  if (vector_tool->function == VECTORS_FINISHED)
    return;

690
  gimp_vectors_freeze (vector_tool->vectors);
691

692
693
694
695
  if ((vector_tool->saved_state & TOGGLE_MASK) != (state & TOGGLE_MASK))
    vector_tool->modifier_lock = FALSE;

  if (!vector_tool->modifier_lock)
696
    {
697
698
699
700
701
702
703
704
      if (state & TOGGLE_MASK)
        {
          vector_tool->restriction = GIMP_ANCHOR_FEATURE_SYMMETRIC;
        }
      else
        {
          vector_tool->restriction = GIMP_ANCHOR_FEATURE_NONE;
        }
705
706
    }

707
708
  switch (vector_tool->function)
    {
709
710
    case VECTORS_MOVE_ANCHOR:
    case VECTORS_MOVE_HANDLE:
711
712
713
      anchor = vector_tool->cur_anchor;

      if (anchor)
714
715
716
717
718
719
        {
          gimp_stroke_anchor_move_absolute (vector_tool->cur_stroke,
                                            vector_tool->cur_anchor,
                                            coords, vector_tool->restriction);
          vector_tool->undo_motion = TRUE;
        }
720
721
722
      break;

    case VECTORS_MOVE_CURVE:
723
724
725
726
727
      if (options->polygonal)
        {
          gimp_vector_tool_move_selected_anchors (vector_tool,
                                               coords->x - vector_tool->last_x,
                                               coords->y - vector_tool->last_y);
728
          vector_tool->undo_motion = TRUE;
729
730
731
732
733
734
735
        }
      else
        {
          gimp_stroke_point_move_absolute (vector_tool->cur_stroke,
                                           vector_tool->cur_anchor,
                                           vector_tool->cur_position,
                                           coords, vector_tool->restriction);
736
          vector_tool->undo_motion = TRUE;
737
        }
738
      break;
739

740
741
742
743
    case VECTORS_MOVE_ANCHORSET:
      gimp_vector_tool_move_selected_anchors (vector_tool,
                                              coords->x - vector_tool->last_x,
                                              coords->y - vector_tool->last_y);
744
      vector_tool->undo_motion = TRUE;
745
746
      break;

747
    case VECTORS_MOVE_STROKE:
748
749
750
751
752
      if (vector_tool->cur_stroke)
        {
          gimp_stroke_translate (vector_tool->cur_stroke,
                                 coords->x - vector_tool->last_x,
                                 coords->y - vector_tool->last_y);
753
          vector_tool->undo_motion = TRUE;
754
755
756
757
758
759
        }
      else if (vector_tool->sel_stroke)
        {
          gimp_stroke_translate (vector_tool->sel_stroke,
                                 coords->x - vector_tool->last_x,
                                 coords->y - vector_tool->last_y);
760
          vector_tool->undo_motion = TRUE;
761
        }
762
763
764
765
766
767
      break;

    case VECTORS_MOVE_VECTORS:
      gimp_item_translate (GIMP_ITEM (vector_tool->vectors),
                           coords->x - vector_tool->last_x,
                           coords->y - vector_tool->last_y, FALSE);
768
      vector_tool->undo_motion = TRUE;
769
770
      break;

771
772
773
774
    default:
      break;
    }

775
776
777
  vector_tool->last_x = coords->x;
  vector_tool->last_y = coords->y;

778
  gimp_vectors_thaw (vector_tool->vectors);
779
780
}

781
static gboolean
782
gimp_vector_tool_key_press (GimpTool     *tool,
783
784
785
                            GdkEventKey  *kevent,
                            GimpDisplay  *gdisp)
{
786
787
788
789
790
791
792
  GimpVectorTool    *vector_tool = GIMP_VECTOR_TOOL (tool);
  GimpDrawTool      *draw_tool   = GIMP_DRAW_TOOL (tool);
  GimpVectorOptions *options;

  GimpDisplayShell  *shell;
  gdouble            xdist, ydist;
  gdouble            pixels = 1.0;
793

794
  if (! vector_tool->vectors)
795
    return FALSE;
796
797
798
799
800
801
802
803
804
805
806
807
808

  shell = GIMP_DISPLAY_SHELL (draw_tool->gdisp->shell);

  if (kevent->state & GDK_SHIFT_MASK)
    pixels = 10.0;

  if (kevent->state & GDK_CONTROL_MASK)
    pixels = 50.0;

  if (gdisp == draw_tool->gdisp)
    {
      switch (kevent->keyval)
        {
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
        case GDK_KP_Enter:
        case GDK_Return:
          gimp_vector_tool_to_selection_extended (vector_tool, kevent->state);
          break;

        case GDK_BackSpace:
        case GDK_Delete:
          gimp_vector_tool_delete_selected_anchors (vector_tool);
          break;

        case GDK_Left:
        case GDK_Right:
        case GDK_Up:
        case GDK_Down:
          xdist = FUNSCALEX (shell, pixels);
          ydist = FUNSCALEY (shell, pixels);

          gimp_vector_tool_undo_push (vector_tool, _("Move Anchors"));

          gimp_vectors_freeze (vector_tool->vectors);

          switch (kevent->keyval)
            {
            case GDK_Left:
              gimp_vector_tool_move_selected_anchors (vector_tool, -xdist, 0);
              break;

            case GDK_Right:
              gimp_vector_tool_move_selected_anchors (vector_tool, xdist, 0);
              break;

            case GDK_Up:
              gimp_vector_tool_move_selected_anchors (vector_tool, 0, -ydist);
              break;

            case GDK_Down:
              gimp_vector_tool_move_selected_anchors (vector_tool, 0, ydist);
846
847
              break;

848
849
850
851
852
853
854
855
            default:
              break;
            }

          gimp_vectors_thaw (vector_tool->vectors);
          vector_tool->have_undo = FALSE;
          break;

856
857
858
859
860
861
        case GDK_Escape:
          options = GIMP_VECTOR_OPTIONS (tool->tool_info->tool_options);

          if (options->edit_mode != GIMP_VECTOR_MODE_DESIGN)
            g_object_set (options, "vectors-edit-mode",
                          GIMP_VECTOR_MODE_DESIGN, NULL);
862
          break;
863
864
865

        default:
          return FALSE;
866
867
868
869
        }

      gimp_image_flush (gdisp->gimage);
    }
870
871

  return TRUE;
872
873
}

874
875
876
877
878
879
880
static void
gimp_vector_tool_modifier_key (GimpTool        *tool,
                               GdkModifierType  key,
                               gboolean         press,
                               GdkModifierType  state,
                               GimpDisplay     *gdisp)
{
881
  GimpVectorTool    *vector_tool = GIMP_VECTOR_TOOL (tool);
882
883
  GimpVectorOptions *options;

884
  options = GIMP_VECTOR_OPTIONS (tool->tool_info->tool_options);
885
886
887
888

  if (key == TOGGLE_MASK)
    return;

889
  if (key == INSDEL_MASK || key == MOVE_MASK)
890
    {
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
      GimpVectorMode button_mode;

      button_mode = options->edit_mode;

      if (press)
        {
          if (key == (state & (INSDEL_MASK | MOVE_MASK)))
            {
              /*  first modifier pressed  */

              vector_tool->saved_mode = options->edit_mode;
            }
        }
      else
        {
          if (! (state & (INSDEL_MASK | MOVE_MASK)))
            {
              /*  last modifier released  */

              button_mode = vector_tool->saved_mode;
            }
        }

914
      if (state & MOVE_MASK)
915
        {
916
          button_mode = GIMP_VECTOR_MODE_MOVE;
917
        }
918
      else if (state & INSDEL_MASK)
919
        {
920
          button_mode = GIMP_VECTOR_MODE_EDIT;
921
922
923
924
925
926
        }

      if (button_mode != options->edit_mode)
        {
          g_object_set (options, "vectors-edit-mode", button_mode, NULL);
        }
927
    }
928
929
}

930
931
932
933
934
935
static void
gimp_vector_tool_oper_update (GimpTool        *tool,
                              GimpCoords      *coords,
                              GdkModifierType  state,
                              GimpDisplay     *gdisp)
{
936
  GimpVectorTool    *vector_tool;
937
  GimpDrawTool      *draw_tool;
938
  GimpVectorOptions *options;
939
940
941
942
943
944
945
  GimpAnchor        *anchor     = NULL;
  GimpAnchor        *anchor2    = NULL;
  GimpStroke        *stroke     = NULL;
  gdouble            position   = -1;
  gboolean           on_handle  = FALSE;
  gboolean           on_curve   = FALSE;
  gboolean           on_vectors = FALSE;
946

947
  vector_tool = GIMP_VECTOR_TOOL (tool);
948
  options     = GIMP_VECTOR_OPTIONS (tool->tool_info->tool_options);
949

950
951
  draw_tool = GIMP_DRAW_TOOL (tool);

952
953
  vector_tool->modifier_lock = FALSE;

954
955
  /* are we hovering the current vectors on the current display? */
  if (vector_tool->vectors && GIMP_DRAW_TOOL (tool)->gdisp == gdisp)
956
    {
957
958
959
960
961
962
      on_handle = gimp_draw_tool_on_vectors_handle (GIMP_DRAW_TOOL (tool),
                                                    gdisp,
                                                    vector_tool->vectors,
                                                    coords,
                                                    TARGET, TARGET,
                                                    GIMP_ANCHOR_ANCHOR,
963
                                                    vector_tool->sel_count > 2,
964
                                                    &anchor, &stroke);
965
966

      if (! on_handle)
967
968
969
970
971
972
        on_curve = gimp_draw_tool_on_vectors_curve (GIMP_DRAW_TOOL (tool),
                                                    gdisp,
                                                    vector_tool->vectors,
                                                    coords,
                                                    TARGET, TARGET,
                                                    NULL,
973
974
                                                    &position, &anchor,
                                                    &anchor2, &stroke);
975
976
    }

977
978
979
980
981
982
983
984
  if (on_handle || on_curve)
    {
      vector_tool->cur_vectors = NULL;
    }
  else
    {
      on_vectors = gimp_draw_tool_on_vectors (draw_tool, gdisp, coords,
                                              TARGET, TARGET,
985
                                              NULL, NULL, NULL, NULL, NULL,
986
987
988
                                              &(vector_tool->cur_vectors));
    }

989
990
  vector_tool->cur_position   = position;
  vector_tool->cur_anchor     = anchor;
991
  vector_tool->cur_anchor2    = anchor2;
992
  vector_tool->cur_stroke     = stroke;
993

994
  switch (options->edit_mode)
995
    {
996
    case GIMP_VECTOR_MODE_DESIGN:
997
      if (! vector_tool->vectors || GIMP_DRAW_TOOL (tool)->gdisp != gdisp)
998
        {
999
          if (on_vectors)
1000
1001
1002
1003
1004
1005
1006
1007
1008
            {
              vector_tool->function = VECTORS_SELECT_VECTOR;
            }
          else
            {
              vector_tool->function = VECTORS_CREATE_VECTOR;
              vector_tool->restriction = GIMP_ANCHOR_FEATURE_SYMMETRIC;
              vector_tool->modifier_lock = TRUE;
            }
1009
        }
1010
      else if (on_handle)
1011
        {
1012
          if (anchor->type == GIMP_ANCHOR_ANCHOR)
1013
            {
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
              if (state & TOGGLE_MASK)
                {
                  vector_tool->function = VECTORS_MOVE_ANCHORSET;
                }
              else
                {
                  if (vector_tool->sel_count >= 2 && anchor->selected)
                    vector_tool->function = VECTORS_MOVE_ANCHORSET;
                  else
                    vector_tool->function = VECTORS_MOVE_ANCHOR;
                }
1025
1026
1027
            }
          else
            {
1028
1029
1030
              vector_tool->function = VECTORS_MOVE_HANDLE;
              if (state & TOGGLE_MASK)
                vector_tool->restriction = GIMP_ANCHOR_FEATURE_SYMMETRIC;
1031
              else
1032
                vector_tool->restriction = GIMP_ANCHOR_FEATURE_NONE;
1033
1034
            }
        }
1035
      else if (on_curve)
1036
        {
1037
1038
1039
1040
1041
1042
1043
1044
          if (gimp_stroke_point_is_movable (stroke, anchor, position))
            {
              vector_tool->function = VECTORS_MOVE_CURVE;
              if (state & TOGGLE_MASK)
                vector_tool->restriction = GIMP_ANCHOR_FEATURE_SYMMETRIC;
              else
                vector_tool->restriction = GIMP_ANCHOR_FEATURE_NONE;
            }
1045
          else
1046
1047
1048
            {
              vector_tool->function = VECTORS_FINISHED;
            }
1049
        }
1050
      else
1051
        {
1052
1053
1054
1055
          if (vector_tool->sel_stroke && vector_tool->sel_anchor &&
              gimp_stroke_is_extendable (vector_tool->sel_stroke,
                                         vector_tool->sel_anchor) &&
              !(state & TOGGLE_MASK))
1056
1057
1058
            vector_tool->function = VECTORS_ADD_ANCHOR;
          else
            vector_tool->function = VECTORS_CREATE_STROKE;
1059

1060
1061
          vector_tool->restriction = GIMP_ANCHOR_FEATURE_SYMMETRIC;
          vector_tool->modifier_lock = TRUE;
1062
        }
1063
1064
1065

      break;

1066
    case GIMP_VECTOR_MODE_EDIT:
1067
      if (! vector_tool->vectors || GIMP_DRAW_TOOL (tool)->gdisp != gdisp)
1068
        {
1069
          if (on_vectors)
1070
1071
1072
1073
1074
1075
1076
            {
              vector_tool->function = VECTORS_SELECT_VECTOR;
            }
          else
            {
              vector_tool->function = VECTORS_FINISHED;
            }
1077
        }
1078
      else if (on_handle)
1079
        {
1080
          if (anchor->type == GIMP_ANCHOR_ANCHOR)
1081
            {
1082
1083
1084
1085
1086
              if (!(state & TOGGLE_MASK) && vector_tool->sel_anchor &&
                  vector_tool->sel_anchor != anchor &&
                  gimp_stroke_is_extendable (vector_tool->sel_stroke,
                                             vector_tool->sel_anchor) &&
                  gimp_stroke_is_extendable (stroke, anchor))
1087
                {
1088
                  vector_tool->function = VECTORS_CONNECT_STROKES;
1089
1090
1091
                }
              else
                {
1092
                  if (state & TOGGLE_MASK)
1093
1094
1095
                    {
                      vector_tool->function = VECTORS_DELETE_ANCHOR;
                    }
1096
                  else
1097
1098
1099
1100
1101
1102
                    {
                      if (options->polygonal)
                        vector_tool->function = VECTORS_MOVE_ANCHOR;
                      else
                        vector_tool->function = VECTORS_MOVE_HANDLE;
                    }
1103
                }
1104
1105
1106
            }
          else
            {
1107
              if (state & TOGGLE_MASK)
1108
                vector_tool->function = VECTORS_CONVERT_EDGE;
1109
              else
1110
                vector_tool->function = VECTORS_MOVE_HANDLE;
1111
            }
1112
        }
1113
      else if (on_curve)
1114
        {
1115
          if (state & TOGGLE_MASK)
1116
            {
1117
              vector_tool->function = VECTORS_DELETE_SEGMENT;
1118
            }
1119
          else if (gimp_stroke_anchor_is_insertable (stroke, anchor, position))
Simon Budig's avatar