~ubuntu-branches/ubuntu/maverick/gimp/maverick-updates

« back to all changes in this revision

Viewing changes to app/vectors/gimpvectors.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2005-12-09 19:44:52 UTC
  • Revision ID: james.westby@ubuntu.com-20051209194452-yggpemjlofpjqyf4
Tags: upstream-2.2.9
ImportĀ upstreamĀ versionĀ 2.2.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* The GIMP -- an image manipulation program
 
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 
3
 *
 
4
 * gimpvectors.c
 
5
 * Copyright (C) 2002 Simon Budig  <simon@gimp.org>
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#include <glib-object.h>
 
25
 
 
26
#include "libgimpcolor/gimpcolor.h"
 
27
 
 
28
#include "vectors-types.h"
 
29
 
 
30
#include "core/gimp.h"
 
31
#include "core/gimpcontainer.h"
 
32
#include "core/gimpcontext.h"
 
33
#include "core/gimpdrawable-stroke.h"
 
34
#include "core/gimp-transform-utils.h"
 
35
#include "core/gimpimage.h"
 
36
#include "core/gimpimage-undo-push.h"
 
37
#include "core/gimpmarshal.h"
 
38
#include "core/gimppaintinfo.h"
 
39
#include "core/gimpstrokedesc.h"
 
40
 
 
41
#include "paint/gimppaintcore-stroke.h"
 
42
#include "paint/gimppaintoptions.h"
 
43
 
 
44
#include "gimpanchor.h"
 
45
#include "gimpstroke.h"
 
46
#include "gimpvectors.h"
 
47
#include "gimpvectors-preview.h"
 
48
 
 
49
#include "gimp-intl.h"
 
50
 
 
51
 
 
52
enum
 
53
{
 
54
  FREEZE,
 
55
  THAW,
 
56
  LAST_SIGNAL
 
57
};
 
58
 
 
59
 
 
60
static void       gimp_vectors_class_init   (GimpVectorsClass *klass);
 
61
static void       gimp_vectors_init         (GimpVectors      *vectors);
 
62
 
 
63
static void       gimp_vectors_finalize     (GObject          *object);
 
64
 
 
65
static gint64     gimp_vectors_get_memsize  (GimpObject       *object,
 
66
                                             gint64           *gui_size);
 
67
 
 
68
static gboolean   gimp_vectors_is_attached  (GimpItem         *item);
 
69
static GimpItem * gimp_vectors_duplicate    (GimpItem         *item,
 
70
                                             GType             new_type,
 
71
                                             gboolean          add_alpha);
 
72
static void       gimp_vectors_convert      (GimpItem         *item,
 
73
                                             GimpImage        *dest_image);
 
74
static void       gimp_vectors_translate    (GimpItem         *item,
 
75
                                             gint              offset_x,
 
76
                                             gint              offset_y,
 
77
                                             gboolean          push_undo);
 
78
static void       gimp_vectors_scale        (GimpItem         *item,
 
79
                                             gint              new_width,
 
80
                                             gint              new_height,
 
81
                                             gint              new_offset_x,
 
82
                                             gint              new_offset_y,
 
83
                                             GimpInterpolationType  interp_type,
 
84
                                             GimpProgress     *progress);
 
85
static void       gimp_vectors_resize       (GimpItem         *item,
 
86
                                             GimpContext      *context,
 
87
                                             gint              new_width,
 
88
                                             gint              new_height,
 
89
                                             gint              offset_x,
 
90
                                             gint              offset_y);
 
91
static void       gimp_vectors_flip         (GimpItem         *item,
 
92
                                             GimpContext      *context,
 
93
                                             GimpOrientationType  flip_type,
 
94
                                             gdouble           axis,
 
95
                                             gboolean          clip_result);
 
96
static void       gimp_vectors_rotate       (GimpItem         *item,
 
97
                                             GimpContext      *context,
 
98
                                             GimpRotationType  rotate_type,
 
99
                                             gdouble           center_x,
 
100
                                             gdouble           center_y,
 
101
                                             gboolean          clip_result);
 
102
static void       gimp_vectors_transform    (GimpItem         *item,
 
103
                                             GimpContext      *context,
 
104
                                             const GimpMatrix3 *matrix,
 
105
                                             GimpTransformDirection direction,
 
106
                                             GimpInterpolationType interp_type,
 
107
                                             gboolean          supersample,
 
108
                                             gint              recursion_level,
 
109
                                             gboolean          clip_result,
 
110
                                             GimpProgress     *progress);
 
111
static gboolean   gimp_vectors_stroke       (GimpItem         *item,
 
112
                                             GimpDrawable     *drawable,
 
113
                                             GimpContext      *context,
 
114
                                             GimpStrokeDesc   *stroke_desc);
 
115
 
 
116
static void       gimp_vectors_real_thaw            (GimpVectors       *vectors);
 
117
static void       gimp_vectors_real_stroke_add      (GimpVectors       *vectors,
 
118
                                                     GimpStroke        *stroke);
 
119
static void       gimp_vectors_real_stroke_remove   (GimpVectors       *vectors,
 
120
                                                     GimpStroke        *stroke);
 
121
static GimpStroke * gimp_vectors_real_stroke_get    (const GimpVectors *vectors,
 
122
                                                     const GimpCoords  *coord);
 
123
static GimpStroke *gimp_vectors_real_stroke_get_next(const GimpVectors *vectors,
 
124
                                                     const GimpStroke  *prev);
 
125
static gdouble gimp_vectors_real_stroke_get_length  (const GimpVectors *vectors,
 
126
                                                     const GimpStroke  *prev);
 
127
static GimpAnchor * gimp_vectors_real_anchor_get    (const GimpVectors *vectors,
 
128
                                                     const GimpCoords  *coord,
 
129
                                                     GimpStroke       **ret_stroke);
 
130
static void       gimp_vectors_real_anchor_delete   (GimpVectors       *vectors,
 
131
                                                     GimpAnchor        *anchor);
 
132
static gdouble    gimp_vectors_real_get_length      (const GimpVectors *vectors,
 
133
                                                     const GimpAnchor  *start);
 
134
static gdouble    gimp_vectors_real_get_distance    (const GimpVectors *vectors,
 
135
                                                     const GimpCoords  *coord);
 
136
static gint       gimp_vectors_real_interpolate     (const GimpVectors *vectors,
 
137
                                                     const GimpStroke  *stroke,
 
138
                                                     gdouble            precision,
 
139
                                                     gint               max_points,
 
140
                                                     GimpCoords        *ret_coords);
 
141
static GimpVectors * gimp_vectors_real_make_bezier  (const GimpVectors *vectors);
 
142
 
 
143
 
 
144
/*  private variables  */
 
145
 
 
146
static guint gimp_vectors_signals[LAST_SIGNAL] = { 0 };
 
147
 
 
148
static GimpItemClass *parent_class = NULL;
 
149
 
 
150
 
 
151
GType
 
152
gimp_vectors_get_type (void)
 
153
{
 
154
  static GType vectors_type = 0;
 
155
 
 
156
  if (! vectors_type)
 
157
    {
 
158
      static const GTypeInfo vectors_info =
 
159
      {
 
160
        sizeof (GimpVectorsClass),
 
161
        (GBaseInitFunc) NULL,
 
162
        (GBaseFinalizeFunc) NULL,
 
163
        (GClassInitFunc) gimp_vectors_class_init,
 
164
        NULL,           /* class_finalize */
 
165
        NULL,           /* class_data     */
 
166
        sizeof (GimpVectors),
 
167
        0,              /* n_preallocs    */
 
168
        (GInstanceInitFunc) gimp_vectors_init,
 
169
      };
 
170
 
 
171
      vectors_type = g_type_register_static (GIMP_TYPE_ITEM,
 
172
                                             "GimpVectors",
 
173
                                             &vectors_info, 0);
 
174
    }
 
175
 
 
176
  return vectors_type;
 
177
}
 
178
 
 
179
static void
 
180
gimp_vectors_class_init (GimpVectorsClass *klass)
 
181
{
 
182
  GObjectClass      *object_class;
 
183
  GimpObjectClass   *gimp_object_class;
 
184
  GimpViewableClass *viewable_class;
 
185
  GimpItemClass     *item_class;
 
186
 
 
187
  object_class      = G_OBJECT_CLASS (klass);
 
188
  gimp_object_class = GIMP_OBJECT_CLASS (klass);
 
189
  viewable_class    = GIMP_VIEWABLE_CLASS (klass);
 
190
  item_class        = GIMP_ITEM_CLASS (klass);
 
191
 
 
192
  parent_class = g_type_class_peek_parent (klass);
 
193
 
 
194
  gimp_vectors_signals[FREEZE] =
 
195
    g_signal_new ("freeze",
 
196
                  G_TYPE_FROM_CLASS (klass),
 
197
                  G_SIGNAL_RUN_FIRST,
 
198
                  G_STRUCT_OFFSET (GimpVectorsClass, freeze),
 
199
                  NULL, NULL,
 
200
                  gimp_marshal_VOID__VOID,
 
201
                  G_TYPE_NONE, 0);
 
202
 
 
203
  gimp_vectors_signals[THAW] =
 
204
    g_signal_new ("thaw",
 
205
                  G_TYPE_FROM_CLASS (klass),
 
206
                  G_SIGNAL_RUN_FIRST,
 
207
                  G_STRUCT_OFFSET (GimpVectorsClass, thaw),
 
208
                  NULL, NULL,
 
209
                  gimp_marshal_VOID__VOID,
 
210
                  G_TYPE_NONE, 0);
 
211
 
 
212
  object_class->finalize           = gimp_vectors_finalize;
 
213
 
 
214
  gimp_object_class->get_memsize   = gimp_vectors_get_memsize;
 
215
 
 
216
  viewable_class->get_new_preview  = gimp_vectors_get_new_preview;
 
217
  viewable_class->default_stock_id = "gimp-path";
 
218
 
 
219
  item_class->is_attached          = gimp_vectors_is_attached;
 
220
  item_class->duplicate            = gimp_vectors_duplicate;
 
221
  item_class->convert              = gimp_vectors_convert;
 
222
  item_class->translate            = gimp_vectors_translate;
 
223
  item_class->scale                = gimp_vectors_scale;
 
224
  item_class->resize               = gimp_vectors_resize;
 
225
  item_class->flip                 = gimp_vectors_flip;
 
226
  item_class->rotate               = gimp_vectors_rotate;
 
227
  item_class->transform            = gimp_vectors_transform;
 
228
  item_class->stroke               = gimp_vectors_stroke;
 
229
  item_class->default_name         = _("Path");
 
230
  item_class->rename_desc          = _("Rename Path");
 
231
  item_class->translate_desc       = _("Move Path");
 
232
  item_class->scale_desc           = _("Scale Path");
 
233
  item_class->resize_desc          = _("Resize Path");
 
234
  item_class->flip_desc            = _("Flip Path");
 
235
  item_class->rotate_desc          = _("Rotate Path");
 
236
  item_class->transform_desc       = _("Transform Path");
 
237
  item_class->stroke_desc          = _("Stroke Path");
 
238
 
 
239
  klass->freeze                    = NULL;
 
240
  klass->thaw                      = gimp_vectors_real_thaw;
 
241
 
 
242
  klass->stroke_add                = gimp_vectors_real_stroke_add;
 
243
  klass->stroke_remove             = gimp_vectors_real_stroke_remove;
 
244
  klass->stroke_get                = gimp_vectors_real_stroke_get;
 
245
  klass->stroke_get_next           = gimp_vectors_real_stroke_get_next;
 
246
  klass->stroke_get_length         = gimp_vectors_real_stroke_get_length;
 
247
 
 
248
  klass->anchor_get                = gimp_vectors_real_anchor_get;
 
249
  klass->anchor_delete             = gimp_vectors_real_anchor_delete;
 
250
 
 
251
  klass->get_length                = gimp_vectors_real_get_length;
 
252
  klass->get_distance              = gimp_vectors_real_get_distance;
 
253
  klass->interpolate               = gimp_vectors_real_interpolate;
 
254
 
 
255
  klass->make_bezier               = gimp_vectors_real_make_bezier;
 
256
}
 
257
 
 
258
static void
 
259
gimp_vectors_init (GimpVectors *vectors)
 
260
{
 
261
  GimpItem *item = GIMP_ITEM (vectors);
 
262
 
 
263
  item->visible         = FALSE;
 
264
  vectors->strokes      = NULL;
 
265
  vectors->freeze_count = 0;
 
266
}
 
267
 
 
268
static void
 
269
gimp_vectors_finalize (GObject *object)
 
270
{
 
271
  GimpVectors *vectors = GIMP_VECTORS (object);
 
272
 
 
273
  if (vectors->strokes)
 
274
    {
 
275
      g_list_foreach (vectors->strokes, (GFunc) g_object_unref, NULL);
 
276
      g_list_free (vectors->strokes);
 
277
      vectors->strokes = NULL;
 
278
    }
 
279
 
 
280
  G_OBJECT_CLASS (parent_class)->finalize (object);
 
281
}
 
282
 
 
283
static gint64
 
284
gimp_vectors_get_memsize (GimpObject *object,
 
285
                          gint64     *gui_size)
 
286
{
 
287
  GimpVectors *vectors;
 
288
  GList       *list;
 
289
  gint64       memsize = 0;
 
290
 
 
291
  vectors = GIMP_VECTORS (object);
 
292
 
 
293
  for (list = vectors->strokes; list; list = g_list_next (list))
 
294
    memsize += (gimp_object_get_memsize (GIMP_OBJECT (list->data), gui_size) +
 
295
                sizeof (GList));
 
296
 
 
297
  return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
 
298
                                                                  gui_size);
 
299
}
 
300
 
 
301
static gboolean
 
302
gimp_vectors_is_attached (GimpItem *item)
 
303
{
 
304
  return (GIMP_IS_IMAGE (item->gimage) &&
 
305
          gimp_container_have (item->gimage->vectors, GIMP_OBJECT (item)));
 
306
}
 
307
 
 
308
static GimpItem *
 
309
gimp_vectors_duplicate (GimpItem *item,
 
310
                        GType     new_type,
 
311
                        gboolean  add_alpha)
 
312
{
 
313
  GimpVectors *vectors;
 
314
  GimpItem    *new_item;
 
315
  GimpVectors *new_vectors;
 
316
 
 
317
  g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_VECTORS), NULL);
 
318
 
 
319
  new_item = GIMP_ITEM_CLASS (parent_class)->duplicate (item, new_type,
 
320
                                                        add_alpha);
 
321
 
 
322
  if (! GIMP_IS_VECTORS (new_item))
 
323
    return new_item;
 
324
 
 
325
  vectors     = GIMP_VECTORS (item);
 
326
  new_vectors = GIMP_VECTORS (new_item);
 
327
 
 
328
  gimp_vectors_copy_strokes (vectors, new_vectors);
 
329
 
 
330
  return new_item;
 
331
}
 
332
 
 
333
static void
 
334
gimp_vectors_convert (GimpItem  *item,
 
335
                      GimpImage *dest_image)
 
336
{
 
337
  item->width  = dest_image->width;
 
338
  item->height = dest_image->height;
 
339
 
 
340
  GIMP_ITEM_CLASS (parent_class)->convert (item, dest_image);
 
341
}
 
342
 
 
343
static void
 
344
gimp_vectors_translate (GimpItem *item,
 
345
                        gint      offset_x,
 
346
                        gint      offset_y,
 
347
                        gboolean  push_undo)
 
348
{
 
349
  GimpVectors *vectors = GIMP_VECTORS (item);
 
350
  GList       *list;
 
351
 
 
352
  gimp_vectors_freeze (vectors);
 
353
 
 
354
  if (push_undo)
 
355
    gimp_image_undo_push_vectors_mod (gimp_item_get_image (item),
 
356
                                      _("Move Path"),
 
357
                                      vectors);
 
358
 
 
359
  for (list = vectors->strokes; list; list = g_list_next (list))
 
360
    {
 
361
      GimpStroke *stroke = list->data;
 
362
 
 
363
      gimp_stroke_translate (stroke, offset_x, offset_y);
 
364
    }
 
365
 
 
366
  gimp_vectors_thaw (vectors);
 
367
}
 
368
 
 
369
static void
 
370
gimp_vectors_scale (GimpItem              *item,
 
371
                    gint                   new_width,
 
372
                    gint                   new_height,
 
373
                    gint                   new_offset_x,
 
374
                    gint                   new_offset_y,
 
375
                    GimpInterpolationType  interpolation_type,
 
376
                    GimpProgress          *progress)
 
377
{
 
378
  GimpVectors *vectors = GIMP_VECTORS (item);
 
379
  GimpImage   *image   = gimp_item_get_image (item);
 
380
  GList       *list;
 
381
 
 
382
  gimp_vectors_freeze (vectors);
 
383
 
 
384
  gimp_image_undo_push_vectors_mod (image, NULL, vectors);
 
385
 
 
386
  for (list = vectors->strokes; list; list = g_list_next (list))
 
387
    {
 
388
      GimpStroke *stroke = list->data;
 
389
 
 
390
      gimp_stroke_scale (stroke,
 
391
                         (gdouble) new_width  / (gdouble) item->width,
 
392
                         (gdouble) new_height / (gdouble) item->height);
 
393
      gimp_stroke_translate (stroke, new_offset_x, new_offset_y);
 
394
    }
 
395
 
 
396
  GIMP_ITEM_CLASS (parent_class)->scale (item, image->width, image->height,
 
397
                                         0, 0, interpolation_type, progress);
 
398
 
 
399
  gimp_vectors_thaw (vectors);
 
400
}
 
401
 
 
402
static void
 
403
gimp_vectors_resize (GimpItem    *item,
 
404
                     GimpContext *context,
 
405
                     gint         new_width,
 
406
                     gint         new_height,
 
407
                     gint         offset_x,
 
408
                     gint         offset_y)
 
409
{
 
410
  GimpVectors *vectors = GIMP_VECTORS (item);
 
411
  GimpImage   *image   = gimp_item_get_image (item);
 
412
  GList       *list;
 
413
 
 
414
  gimp_vectors_freeze (vectors);
 
415
 
 
416
  gimp_image_undo_push_vectors_mod (image, NULL, vectors);
 
417
 
 
418
  for (list = vectors->strokes; list; list = g_list_next (list))
 
419
    {
 
420
      GimpStroke *stroke = list->data;
 
421
 
 
422
      gimp_stroke_translate (stroke, offset_x, offset_y);
 
423
    }
 
424
 
 
425
  GIMP_ITEM_CLASS (parent_class)->resize (item, context,
 
426
                                          image->width, image->height, 0, 0);
 
427
 
 
428
  gimp_vectors_thaw (vectors);
 
429
}
 
430
 
 
431
static void
 
432
gimp_vectors_flip (GimpItem            *item,
 
433
                   GimpContext         *context,
 
434
                   GimpOrientationType  flip_type,
 
435
                   gdouble              axis,
 
436
                   gboolean             clip_result)
 
437
{
 
438
  GimpVectors *vectors = GIMP_VECTORS (item);
 
439
  GList       *list;
 
440
  GimpMatrix3  matrix;
 
441
 
 
442
  gimp_transform_matrix_flip (flip_type, axis, &matrix);
 
443
 
 
444
  gimp_vectors_freeze (vectors);
 
445
 
 
446
  gimp_image_undo_push_vectors_mod (gimp_item_get_image (item),
 
447
                                    _("Flip Path"),
 
448
                                    vectors);
 
449
 
 
450
  for (list = vectors->strokes; list; list = g_list_next (list))
 
451
    {
 
452
      GimpStroke *stroke = list->data;
 
453
 
 
454
      gimp_stroke_transform (stroke, &matrix);
 
455
    }
 
456
 
 
457
  gimp_vectors_thaw (vectors);
 
458
}
 
459
 
 
460
static void
 
461
gimp_vectors_rotate (GimpItem         *item,
 
462
                     GimpContext      *context,
 
463
                     GimpRotationType  rotate_type,
 
464
                     gdouble           center_x,
 
465
                     gdouble           center_y,
 
466
                     gboolean          clip_result)
 
467
{
 
468
  GimpVectors *vectors = GIMP_VECTORS (item);
 
469
  GList       *list;
 
470
  GimpMatrix3  matrix;
 
471
  gdouble      angle = 0.0;
 
472
 
 
473
  switch (rotate_type)
 
474
    {
 
475
    case GIMP_ROTATE_90:
 
476
      angle = G_PI_2;
 
477
      break;
 
478
    case GIMP_ROTATE_180:
 
479
      angle = G_PI;
 
480
      break;
 
481
    case GIMP_ROTATE_270:
 
482
      angle = - G_PI_2;
 
483
      break;
 
484
    }
 
485
 
 
486
  gimp_transform_matrix_rotate_center (center_x, center_y, angle, &matrix);
 
487
 
 
488
  gimp_vectors_freeze (vectors);
 
489
 
 
490
  gimp_image_undo_push_vectors_mod (gimp_item_get_image (item),
 
491
                                    _("Rotate Path"),
 
492
                                    vectors);
 
493
 
 
494
  for (list = vectors->strokes; list; list = g_list_next (list))
 
495
    {
 
496
      GimpStroke *stroke = list->data;
 
497
 
 
498
      gimp_stroke_transform (stroke, &matrix);
 
499
    }
 
500
 
 
501
  gimp_vectors_thaw (vectors);
 
502
}
 
503
 
 
504
static void
 
505
gimp_vectors_transform (GimpItem               *item,
 
506
                        GimpContext            *context,
 
507
                        const GimpMatrix3      *matrix,
 
508
                        GimpTransformDirection  direction,
 
509
                        GimpInterpolationType   interpolation_type,
 
510
                        gboolean                supersample,
 
511
                        gint                    recursion_level,
 
512
                        gboolean                clip_result,
 
513
                        GimpProgress           *progress)
 
514
{
 
515
  GimpVectors *vectors = GIMP_VECTORS (item);
 
516
  GimpMatrix3  local_matrix;
 
517
  GList       *list;
 
518
 
 
519
  gimp_vectors_freeze (vectors);
 
520
 
 
521
  gimp_image_undo_push_vectors_mod (gimp_item_get_image (item),
 
522
                                    _("Transform Path"),
 
523
                                    vectors);
 
524
 
 
525
  local_matrix = *matrix;
 
526
 
 
527
  if (direction == GIMP_TRANSFORM_BACKWARD)
 
528
    gimp_matrix3_invert (&local_matrix);
 
529
 
 
530
  for (list = vectors->strokes; list; list = g_list_next (list))
 
531
    {
 
532
      GimpStroke *stroke = list->data;
 
533
 
 
534
      gimp_stroke_transform (stroke, &local_matrix);
 
535
    }
 
536
 
 
537
  gimp_vectors_thaw (vectors);
 
538
}
 
539
 
 
540
static gboolean
 
541
gimp_vectors_stroke (GimpItem       *item,
 
542
                     GimpDrawable   *drawable,
 
543
                     GimpContext    *context,
 
544
                     GimpStrokeDesc *stroke_desc)
 
545
{
 
546
  GimpVectors *vectors = GIMP_VECTORS (item);
 
547
  gboolean     retval  = FALSE;
 
548
 
 
549
  if (! vectors->strokes)
 
550
    {
 
551
      g_message (_("Cannot stroke empty path."));
 
552
      return FALSE;
 
553
    }
 
554
 
 
555
  switch (stroke_desc->method)
 
556
    {
 
557
    case GIMP_STROKE_METHOD_LIBART:
 
558
      gimp_drawable_stroke_vectors (drawable,
 
559
                                    stroke_desc->stroke_options,
 
560
                                    vectors);
 
561
      retval = TRUE;
 
562
      break;
 
563
 
 
564
    case GIMP_STROKE_METHOD_PAINT_CORE:
 
565
      {
 
566
        GimpPaintCore *core;
 
567
 
 
568
        core = g_object_new (stroke_desc->paint_info->paint_type, NULL);
 
569
 
 
570
        retval = gimp_paint_core_stroke_vectors (core, drawable,
 
571
                                                 stroke_desc->paint_options,
 
572
                                                 vectors);
 
573
 
 
574
        g_object_unref (core);
 
575
      }
 
576
      break;
 
577
 
 
578
    default:
 
579
      g_return_val_if_reached (FALSE);
 
580
    }
 
581
 
 
582
  return retval;
 
583
}
 
584
 
 
585
static void
 
586
gimp_vectors_real_thaw (GimpVectors *vectors)
 
587
{
 
588
  gimp_viewable_invalidate_preview (GIMP_VIEWABLE (vectors));
 
589
}
 
590
 
 
591
 
 
592
/*  public functions  */
 
593
 
 
594
GimpVectors *
 
595
gimp_vectors_new (GimpImage   *gimage,
 
596
                  const gchar *name)
 
597
{
 
598
  GimpVectors *vectors;
 
599
 
 
600
  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
 
601
 
 
602
  vectors = g_object_new (GIMP_TYPE_VECTORS, NULL);
 
603
 
 
604
  gimp_item_configure (GIMP_ITEM (vectors), gimage,
 
605
                       0, 0, gimage->width, gimage->height,
 
606
                       name);
 
607
 
 
608
  return vectors;
 
609
}
 
610
 
 
611
void
 
612
gimp_vectors_freeze (GimpVectors *vectors)
 
613
{
 
614
  g_return_if_fail (GIMP_IS_VECTORS (vectors));
 
615
 
 
616
  vectors->freeze_count++;
 
617
 
 
618
  if (vectors->freeze_count == 1)
 
619
    g_signal_emit (vectors, gimp_vectors_signals[FREEZE], 0);
 
620
}
 
621
 
 
622
void
 
623
gimp_vectors_thaw (GimpVectors *vectors)
 
624
{
 
625
  g_return_if_fail (GIMP_IS_VECTORS (vectors));
 
626
  g_return_if_fail (vectors->freeze_count > 0);
 
627
 
 
628
  vectors->freeze_count--;
 
629
 
 
630
  if (vectors->freeze_count == 0)
 
631
    g_signal_emit (vectors, gimp_vectors_signals[THAW], 0);
 
632
}
 
633
 
 
634
void
 
635
gimp_vectors_copy_strokes (const GimpVectors *src_vectors,
 
636
                           GimpVectors       *dest_vectors)
 
637
{
 
638
  g_return_if_fail (GIMP_IS_VECTORS (src_vectors));
 
639
  g_return_if_fail (GIMP_IS_VECTORS (dest_vectors));
 
640
 
 
641
  gimp_vectors_freeze (dest_vectors);
 
642
 
 
643
  if (dest_vectors->strokes)
 
644
    {
 
645
      g_list_foreach (dest_vectors->strokes, (GFunc) g_object_unref, NULL);
 
646
      g_list_free (dest_vectors->strokes);
 
647
    }
 
648
 
 
649
  dest_vectors->strokes = NULL;
 
650
 
 
651
  gimp_vectors_add_strokes (src_vectors, dest_vectors);
 
652
 
 
653
  gimp_vectors_thaw (dest_vectors);
 
654
}
 
655
 
 
656
 
 
657
void
 
658
gimp_vectors_add_strokes (const GimpVectors *src_vectors,
 
659
                          GimpVectors       *dest_vectors)
 
660
{
 
661
  GList *current_lstroke;
 
662
  GList *strokes_copy;
 
663
 
 
664
  g_return_if_fail (GIMP_IS_VECTORS (src_vectors));
 
665
  g_return_if_fail (GIMP_IS_VECTORS (dest_vectors));
 
666
 
 
667
  gimp_vectors_freeze (dest_vectors);
 
668
 
 
669
  strokes_copy = g_list_copy (src_vectors->strokes);
 
670
  current_lstroke = strokes_copy;
 
671
 
 
672
  while (current_lstroke)
 
673
    {
 
674
      current_lstroke->data = gimp_stroke_duplicate (current_lstroke->data);
 
675
      current_lstroke = g_list_next (current_lstroke);
 
676
    }
 
677
 
 
678
  dest_vectors->strokes = g_list_concat (dest_vectors->strokes, strokes_copy);
 
679
 
 
680
  gimp_vectors_thaw (dest_vectors);
 
681
}
 
682
 
 
683
 
 
684
/* Calling the virtual functions */
 
685
 
 
686
void
 
687
gimp_vectors_stroke_add (GimpVectors *vectors,
 
688
                         GimpStroke  *stroke)
 
689
{
 
690
  g_return_if_fail (GIMP_IS_VECTORS (vectors));
 
691
  g_return_if_fail (GIMP_IS_STROKE (stroke));
 
692
 
 
693
  gimp_vectors_freeze (vectors);
 
694
 
 
695
  GIMP_VECTORS_GET_CLASS (vectors)->stroke_add (vectors, stroke);
 
696
 
 
697
  gimp_vectors_thaw (vectors);
 
698
}
 
699
 
 
700
static void
 
701
gimp_vectors_real_stroke_add (GimpVectors *vectors,
 
702
                              GimpStroke  *stroke)
 
703
{
 
704
  /*  Don't g_list_prepend() here.  See ChangeLog 2003-05-21 --Mitch  */
 
705
 
 
706
  vectors->strokes = g_list_append (vectors->strokes, stroke);
 
707
  g_object_ref (stroke);
 
708
}
 
709
 
 
710
void
 
711
gimp_vectors_stroke_remove (GimpVectors *vectors,
 
712
                            GimpStroke  *stroke)
 
713
{
 
714
  g_return_if_fail (GIMP_IS_VECTORS (vectors));
 
715
  g_return_if_fail (GIMP_IS_STROKE (stroke));
 
716
 
 
717
  gimp_vectors_freeze (vectors);
 
718
 
 
719
  GIMP_VECTORS_GET_CLASS (vectors)->stroke_remove (vectors, stroke);
 
720
 
 
721
  gimp_vectors_thaw (vectors);
 
722
}
 
723
 
 
724
static void
 
725
gimp_vectors_real_stroke_remove (GimpVectors *vectors,
 
726
                                 GimpStroke  *stroke)
 
727
{
 
728
  GList *list;
 
729
 
 
730
  list = g_list_find (vectors->strokes, stroke);
 
731
 
 
732
  if (list)
 
733
    {
 
734
      vectors->strokes = g_list_delete_link (vectors->strokes, list);
 
735
      g_object_unref (stroke);
 
736
    }
 
737
}
 
738
 
 
739
 
 
740
GimpStroke *
 
741
gimp_vectors_stroke_get (const GimpVectors *vectors,
 
742
                         const GimpCoords  *coord)
 
743
{
 
744
  g_return_val_if_fail (GIMP_IS_VECTORS (vectors), NULL);
 
745
 
 
746
  return GIMP_VECTORS_GET_CLASS (vectors)->stroke_get (vectors, coord);
 
747
}
 
748
 
 
749
static GimpStroke *
 
750
gimp_vectors_real_stroke_get (const GimpVectors *vectors,
 
751
                              const GimpCoords  *coord)
 
752
{
 
753
  GList      *stroke;
 
754
  gdouble     mindist   = G_MAXDOUBLE;
 
755
  GimpStroke *minstroke = NULL;
 
756
 
 
757
  for (stroke = vectors->strokes; stroke; stroke = g_list_next (stroke))
 
758
    {
 
759
      GimpAnchor *anchor = gimp_stroke_anchor_get (stroke->data, coord);
 
760
 
 
761
      if (anchor)
 
762
        {
 
763
          gdouble dx, dy;
 
764
 
 
765
          dx = coord->x - anchor->position.x;
 
766
          dy = coord->y - anchor->position.y;
 
767
 
 
768
          if (mindist > dx * dx + dy * dy)
 
769
            {
 
770
              mindist   = dx * dx + dy * dy;
 
771
              minstroke = GIMP_STROKE (stroke->data);
 
772
            }
 
773
        }
 
774
    }
 
775
 
 
776
  return minstroke;
 
777
}
 
778
 
 
779
 
 
780
GimpStroke *
 
781
gimp_vectors_stroke_get_next (const GimpVectors *vectors,
 
782
                              const GimpStroke  *prev)
 
783
{
 
784
  g_return_val_if_fail (GIMP_IS_VECTORS (vectors), NULL);
 
785
 
 
786
  return GIMP_VECTORS_GET_CLASS (vectors)->stroke_get_next (vectors, prev);
 
787
}
 
788
 
 
789
static GimpStroke *
 
790
gimp_vectors_real_stroke_get_next (const GimpVectors *vectors,
 
791
                                   const GimpStroke  *prev)
 
792
{
 
793
  if (! prev)
 
794
    {
 
795
      return vectors->strokes ? vectors->strokes->data : NULL;
 
796
    }
 
797
  else
 
798
    {
 
799
      GList *stroke;
 
800
 
 
801
      stroke = g_list_find (vectors->strokes, prev);
 
802
 
 
803
      g_return_val_if_fail (stroke != NULL, NULL);
 
804
 
 
805
      return stroke->next ? GIMP_STROKE (stroke->next->data) : NULL;
 
806
    }
 
807
}
 
808
 
 
809
 
 
810
gdouble
 
811
gimp_vectors_stroke_get_length (const GimpVectors *vectors,
 
812
                                const GimpStroke  *prev)
 
813
{
 
814
  g_return_val_if_fail (GIMP_IS_VECTORS (vectors), 0.0);
 
815
 
 
816
  return GIMP_VECTORS_GET_CLASS (vectors)->stroke_get_length (vectors, prev);
 
817
}
 
818
 
 
819
static gdouble
 
820
gimp_vectors_real_stroke_get_length (const GimpVectors *vectors,
 
821
                                     const GimpStroke  *prev)
 
822
{
 
823
  g_printerr ("gimp_vectors_stroke_get_length: default implementation\n");
 
824
 
 
825
  return 0.0;
 
826
}
 
827
 
 
828
 
 
829
GimpAnchor *
 
830
gimp_vectors_anchor_get (const GimpVectors *vectors,
 
831
                         const GimpCoords  *coord,
 
832
                         GimpStroke       **ret_stroke)
 
833
{
 
834
  g_return_val_if_fail (GIMP_IS_VECTORS (vectors), NULL);
 
835
 
 
836
  return GIMP_VECTORS_GET_CLASS (vectors)->anchor_get (vectors, coord,
 
837
                                                       ret_stroke);
 
838
}
 
839
 
 
840
static GimpAnchor *
 
841
gimp_vectors_real_anchor_get (const GimpVectors *vectors,
 
842
                              const GimpCoords  *coord,
 
843
                              GimpStroke       **ret_stroke)
 
844
{
 
845
  gdouble     dx, dy, mindist;
 
846
  GList      *stroke;
 
847
  GimpAnchor *anchor    = NULL;
 
848
  GimpAnchor *minanchor = NULL;
 
849
 
 
850
  mindist = -1;
 
851
 
 
852
  for (stroke = vectors->strokes; stroke; stroke = g_list_next (stroke))
 
853
    {
 
854
      anchor = gimp_stroke_anchor_get (GIMP_STROKE (stroke->data), coord);
 
855
 
 
856
      if (anchor)
 
857
        {
 
858
          dx = coord->x - anchor->position.x;
 
859
          dy = coord->y - anchor->position.y;
 
860
 
 
861
          if (mindist > dx * dx + dy * dy || mindist < 0)
 
862
            {
 
863
              mindist   = dx * dx + dy * dy;
 
864
              minanchor = anchor;
 
865
 
 
866
              if (ret_stroke)
 
867
                *ret_stroke = stroke->data;
 
868
            }
 
869
        }
 
870
    }
 
871
 
 
872
  return minanchor;
 
873
}
 
874
 
 
875
 
 
876
void
 
877
gimp_vectors_anchor_delete (GimpVectors *vectors,
 
878
                            GimpAnchor  *anchor)
 
879
{
 
880
  g_return_if_fail (GIMP_IS_VECTORS (vectors));
 
881
  g_return_if_fail (anchor != NULL);
 
882
 
 
883
  GIMP_VECTORS_GET_CLASS (vectors)->anchor_delete (vectors, anchor);
 
884
}
 
885
 
 
886
static void
 
887
gimp_vectors_real_anchor_delete (GimpVectors *vectors,
 
888
                                 GimpAnchor  *anchor)
 
889
{
 
890
}
 
891
 
 
892
 
 
893
void
 
894
gimp_vectors_anchor_select (GimpVectors *vectors,
 
895
                            GimpStroke  *target_stroke,
 
896
                            GimpAnchor  *anchor,
 
897
                            gboolean     selected,
 
898
                            gboolean     exclusive)
 
899
{
 
900
  GList      *stroke_list;
 
901
  GimpStroke *stroke;
 
902
 
 
903
  for (stroke_list = vectors->strokes; stroke_list;
 
904
       stroke_list = g_list_next (stroke_list))
 
905
    {
 
906
      stroke = GIMP_STROKE (stroke_list->data);
 
907
      gimp_stroke_anchor_select (stroke,
 
908
                                 stroke == target_stroke ? anchor : NULL,
 
909
                                 selected, exclusive);
 
910
    }
 
911
}
 
912
 
 
913
 
 
914
gdouble
 
915
gimp_vectors_get_length (const GimpVectors *vectors,
 
916
                         const GimpAnchor  *start)
 
917
{
 
918
  g_return_val_if_fail (GIMP_IS_VECTORS (vectors), 0.0);
 
919
 
 
920
  return GIMP_VECTORS_GET_CLASS (vectors)->get_length (vectors, start);
 
921
}
 
922
 
 
923
static gdouble
 
924
gimp_vectors_real_get_length (const GimpVectors *vectors,
 
925
                              const GimpAnchor  *start)
 
926
{
 
927
  g_printerr ("gimp_vectors_get_length: default implementation\n");
 
928
 
 
929
  return 0;
 
930
}
 
931
 
 
932
 
 
933
gdouble
 
934
gimp_vectors_get_distance (const GimpVectors *vectors,
 
935
                           const GimpCoords  *coord)
 
936
{
 
937
  g_return_val_if_fail (GIMP_IS_VECTORS (vectors), 0.0);
 
938
 
 
939
  return GIMP_VECTORS_GET_CLASS (vectors)->get_distance (vectors, coord);
 
940
}
 
941
 
 
942
static gdouble
 
943
gimp_vectors_real_get_distance (const GimpVectors *vectors,
 
944
                                const GimpCoords  *coord)
 
945
{
 
946
  g_printerr ("gimp_vectors_get_distance: default implementation\n");
 
947
 
 
948
  return 0;
 
949
}
 
950
 
 
951
gboolean
 
952
gimp_vectors_bounds (const GimpVectors  *vectors,
 
953
                     gdouble            *x1,
 
954
                     gdouble            *y1,
 
955
                     gdouble            *x2,
 
956
                     gdouble            *y2)
 
957
{
 
958
  GArray     *stroke_coords;
 
959
  GimpStroke *cur_stroke;
 
960
  gint        i;
 
961
  gboolean    has_strokes = FALSE;
 
962
  gboolean    closed;
 
963
  GimpCoords  point;
 
964
 
 
965
  g_return_val_if_fail (GIMP_IS_VECTORS (vectors), FALSE);
 
966
  g_return_val_if_fail (x1 != NULL, FALSE);
 
967
  g_return_val_if_fail (y1 != NULL, FALSE);
 
968
  g_return_val_if_fail (x2 != NULL, FALSE);
 
969
  g_return_val_if_fail (y2 != NULL, FALSE);
 
970
 
 
971
  for (cur_stroke = gimp_vectors_stroke_get_next (vectors, NULL);
 
972
       cur_stroke;
 
973
       cur_stroke = gimp_vectors_stroke_get_next (vectors, cur_stroke))
 
974
    {
 
975
      stroke_coords = gimp_stroke_interpolate (cur_stroke, 1.0, &closed);
 
976
 
 
977
      if (stroke_coords)
 
978
        {
 
979
          if (! has_strokes && stroke_coords->len > 0)
 
980
            {
 
981
              has_strokes = TRUE;
 
982
              point = g_array_index (stroke_coords, GimpCoords, 0);
 
983
              *x1 = *x2 = point.x;
 
984
              *y1 = *y2 = point.y;
 
985
            }
 
986
 
 
987
          for (i=0; i < stroke_coords->len; i++)
 
988
            {
 
989
              point = g_array_index (stroke_coords, GimpCoords, i);
 
990
              *x1 = MIN (*x1, point.x);
 
991
              *y1 = MIN (*y1, point.y);
 
992
              *x2 = MAX (*x2, point.x);
 
993
              *y2 = MAX (*y2, point.y);
 
994
            }
 
995
          g_array_free (stroke_coords, TRUE);
 
996
        }
 
997
    }
 
998
 
 
999
  return has_strokes;
 
1000
}
 
1001
 
 
1002
gint
 
1003
gimp_vectors_interpolate (const GimpVectors *vectors,
 
1004
                          const GimpStroke  *stroke,
 
1005
                          gdouble            precision,
 
1006
                          gint               max_points,
 
1007
                          GimpCoords        *ret_coords)
 
1008
{
 
1009
  g_return_val_if_fail (GIMP_IS_VECTORS (vectors), 0);
 
1010
 
 
1011
  return GIMP_VECTORS_GET_CLASS (vectors)->interpolate (vectors, stroke,
 
1012
                                                        precision, max_points,
 
1013
                                                        ret_coords);
 
1014
}
 
1015
 
 
1016
static gint
 
1017
gimp_vectors_real_interpolate (const GimpVectors *vectors,
 
1018
                               const GimpStroke  *stroke,
 
1019
                               gdouble            precision,
 
1020
                               gint               max_points,
 
1021
                               GimpCoords        *ret_coords)
 
1022
{
 
1023
  g_printerr ("gimp_vectors_interpolate: default implementation\n");
 
1024
 
 
1025
  return 0;
 
1026
}
 
1027
 
 
1028
 
 
1029
GimpVectors *
 
1030
gimp_vectors_make_bezier (const GimpVectors *vectors)
 
1031
{
 
1032
  g_return_val_if_fail (GIMP_IS_VECTORS (vectors), NULL);
 
1033
 
 
1034
  return GIMP_VECTORS_GET_CLASS (vectors)->make_bezier (vectors);
 
1035
}
 
1036
 
 
1037
static GimpVectors *
 
1038
gimp_vectors_real_make_bezier (const GimpVectors *vectors)
 
1039
{
 
1040
  g_printerr ("gimp_vectors_make_bezier: default implementation\n");
 
1041
 
 
1042
  return NULL;
 
1043
}
 
1044