gimpdrawtool.c 37.3 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
2 3
 * Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis, and others
 *
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7 8 9 10 11 12 13 14
 * (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
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 17 18 19
 */

#include "config.h"

Mukund Sivaraman's avatar
Mukund Sivaraman committed
20
#include <string.h>
Sven Neumann's avatar
Sven Neumann committed
21

22
#include <gegl.h>
23 24
#include <gtk/gtk.h>

25 26
#include "libgimpmath/gimpmath.h"

27
#include "tools-types.h"
28

29 30
#include "core/gimpimage.h"

31
#include "vectors/gimpanchor.h"
32 33 34
#include "vectors/gimpstroke.h"
#include "vectors/gimpvectors.h"

35
#include "display/gimpcanvas.h"
36
#include "display/gimpcanvasarc.h"
37
#include "display/gimpcanvasboundary.h"
38
#include "display/gimpcanvascorner.h"
39
#include "display/gimpcanvasgroup.h"
40
#include "display/gimpcanvasguide.h"
41 42
#include "display/gimpcanvashandle.h"
#include "display/gimpcanvasline.h"
43
#include "display/gimpcanvaspen.h"
44
#include "display/gimpcanvaspolygon.h"
45
#include "display/gimpcanvasrectangle.h"
46
#include "display/gimpcanvassamplepoint.h"
47
#include "display/gimpcanvastextcursor.h"
48
#include "display/gimpdisplay.h"
Michael Natterer's avatar
Michael Natterer committed
49
#include "display/gimpdisplayshell.h"
50
#include "display/gimpdisplayshell-expose.h"
51
#include "display/gimpdisplayshell-items.h"
52
#include "display/gimpdisplayshell-transform.h"
Michael Natterer's avatar
Michael Natterer committed
53

54
#include "gimpdrawtool.h"
55 56


57 58
static void          gimp_draw_tool_dispose      (GObject        *object);

59 60 61 62 63 64 65
static gboolean      gimp_draw_tool_has_display  (GimpTool       *tool,
                                                  GimpDisplay    *display);
static GimpDisplay * gimp_draw_tool_has_image    (GimpTool       *tool,
                                                  GimpImage      *image);
static void          gimp_draw_tool_control      (GimpTool       *tool,
                                                  GimpToolAction  action,
                                                  GimpDisplay    *display);
66

67
static void          gimp_draw_tool_draw         (GimpDrawTool   *draw_tool);
68
static void          gimp_draw_tool_undraw       (GimpDrawTool   *draw_tool);
69 70
static void          gimp_draw_tool_real_draw    (GimpDrawTool   *draw_tool);

71
static inline void   gimp_draw_tool_shift_to_north_west
72 73 74 75 76 77 78
                                                 (gdouble         x,
                                                  gdouble         y,
                                                  gint            handle_width,
                                                  gint            handle_height,
                                                  GtkAnchorType   anchor,
                                                  gdouble        *shifted_x,
                                                  gdouble        *shifted_y);
79
static inline void   gimp_draw_tool_shift_to_center
80 81 82 83 84 85 86
                                                 (gdouble         x,
                                                  gdouble         y,
                                                  gint            handle_width,
                                                  gint            handle_height,
                                                  GtkAnchorType   anchor,
                                                  gdouble        *shifted_x,
                                                  gdouble        *shifted_y);
87 88


89
G_DEFINE_TYPE (GimpDrawTool, gimp_draw_tool, GIMP_TYPE_TOOL)
90

91
#define parent_class gimp_draw_tool_parent_class
92

93 94 95 96

static void
gimp_draw_tool_class_init (GimpDrawToolClass *klass)
{
97 98 99 100
  GObjectClass  *object_class = G_OBJECT_CLASS (klass);
  GimpToolClass *tool_class   = GIMP_TOOL_CLASS (klass);

  object_class->dispose   = gimp_draw_tool_dispose;
101

102 103 104
  tool_class->has_display = gimp_draw_tool_has_display;
  tool_class->has_image   = gimp_draw_tool_has_image;
  tool_class->control     = gimp_draw_tool_control;
105

106
  klass->draw             = gimp_draw_tool_real_draw;
107 108
}

109
static void
110
gimp_draw_tool_init (GimpDrawTool *draw_tool)
111
{
112
  draw_tool->display      = NULL;
113
  draw_tool->paused_count = 0;
114
  draw_tool->item         = NULL;
115 116
}

117 118 119 120 121 122
static void
gimp_draw_tool_dispose (GObject *object)
{
  G_OBJECT_CLASS (parent_class)->dispose (object);
}

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
static gboolean
gimp_draw_tool_has_display (GimpTool    *tool,
                            GimpDisplay *display)
{
  GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);

  return (display == draw_tool->display ||
          GIMP_TOOL_CLASS (parent_class)->has_display (tool, display));
}

static GimpDisplay *
gimp_draw_tool_has_image (GimpTool  *tool,
                          GimpImage *image)
{
  GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
  GimpDisplay  *display;

  display = GIMP_TOOL_CLASS (parent_class)->has_image (tool, image);

  if (! display && draw_tool->display)
    {
144
      if (image && gimp_display_get_image (draw_tool->display) == image)
145 146 147 148 149 150 151 152 153 154
        display = draw_tool->display;

      /*  NULL image means any display  */
      if (! image)
        display = draw_tool->display;
    }

  return display;
}

155
static void
156
gimp_draw_tool_control (GimpTool       *tool,
157 158
                        GimpToolAction  action,
                        GimpDisplay    *display)
159
{
160
  GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
161 162 163

  switch (action)
    {
164 165
    case GIMP_TOOL_ACTION_PAUSE:
    case GIMP_TOOL_ACTION_RESUME:
166 167
      break;

168
    case GIMP_TOOL_ACTION_HALT:
169 170 171
      gimp_draw_tool_stop (draw_tool);
      break;
    }
172

173
  GIMP_TOOL_CLASS (parent_class)->control (tool, action, display);
174 175
}

176 177 178
static void
gimp_draw_tool_draw (GimpDrawTool *draw_tool)
{
179
  if (draw_tool->display && draw_tool->paused_count == 0)
180
    {
Michael Natterer's avatar
Michael Natterer committed
181
      gimp_draw_tool_undraw (draw_tool);
182 183 184

      GIMP_DRAW_TOOL_GET_CLASS (draw_tool)->draw (draw_tool);

185 186 187 188 189 190 191 192 193 194 195
      if (draw_tool->group_stack)
        {
          g_warning ("%s: draw_tool->group_stack not empty after calling "
                     "GimpDrawTool::draw() of %s",
                     G_STRFUNC,
                     g_type_name (G_TYPE_FROM_INSTANCE (draw_tool)));

          while (draw_tool->group_stack)
            gimp_draw_tool_pop_group (draw_tool);
        }

196 197
      if (draw_tool->item)
        {
Michael Natterer's avatar
Michael Natterer committed
198 199
          GimpDisplayShell *shell = gimp_display_get_shell (draw_tool->display);

200 201
          gimp_display_shell_add_item (shell, draw_tool->item);
        }
202 203 204 205 206 207
    }
}

static void
gimp_draw_tool_undraw (GimpDrawTool *draw_tool)
{
208
  if (draw_tool->display && draw_tool->item)
209
    {
210 211 212
      GimpDisplayShell *shell = gimp_display_get_shell (draw_tool->display);

      gimp_display_shell_remove_item (shell, draw_tool->item);
Michael Natterer's avatar
Michael Natterer committed
213 214
      g_object_unref (draw_tool->item);
      draw_tool->item = NULL;
215
    }
216 217
}

218 219 220
static void
gimp_draw_tool_real_draw (GimpDrawTool *draw_tool)
{
221
  /* the default implementation does nothing */
222 223
}

224
void
225
gimp_draw_tool_start (GimpDrawTool *draw_tool,
226
                      GimpDisplay  *display)
227
{
228
  g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
229
  g_return_if_fail (GIMP_IS_DISPLAY (display));
230

231
  gimp_draw_tool_stop (draw_tool);
232

233
  draw_tool->display = display;
234

235
  gimp_draw_tool_draw (draw_tool);
236 237 238
}

void
239
gimp_draw_tool_stop (GimpDrawTool *draw_tool)
240
{
241 242
  g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));

243
  gimp_draw_tool_undraw (draw_tool);
244

245
  draw_tool->display = NULL;
246 247
}

248 249 250 251 252
gboolean
gimp_draw_tool_is_active (GimpDrawTool *draw_tool)
{
  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), FALSE);

253
  return draw_tool->display != NULL;
254 255
}

256 257 258
void
gimp_draw_tool_pause (GimpDrawTool *draw_tool)
{
259 260
  g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));

261 262
  draw_tool->paused_count++;
}
263 264

void
265
gimp_draw_tool_resume (GimpDrawTool *draw_tool)
266
{
267
  g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
268
  g_return_if_fail (draw_tool->paused_count > 0);
269

270
  draw_tool->paused_count--;
271

272
  gimp_draw_tool_draw (draw_tool);
273 274
}

275 276 277 278 279 280
/**
 * gimp_draw_tool_calc_distance:
 * @draw_tool: a #GimpDrawTool
 * @display:   a #GimpDisplay
 * @x1:        start point X in image coordinates
 * @y1:        start point Y in image coordinates
281 282
 * @x2:        end point X in image coordinates
 * @y2:        end point Y in image coordinates
283
 *
284 285 286
 * If you just need to compare distances, consider to use
 * gimp_draw_tool_calc_distance_square() instead.
 *
287 288
 * Returns: the distance between the given points in display coordinates
 **/
289 290
gdouble
gimp_draw_tool_calc_distance (GimpDrawTool *draw_tool,
291
                              GimpDisplay  *display,
292 293 294 295
                              gdouble       x1,
                              gdouble       y1,
                              gdouble       x2,
                              gdouble       y2)
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
{
  return sqrt (gimp_draw_tool_calc_distance_square (draw_tool, display,
                                                    x1, y1, x2, y2));
}

/**
 * gimp_draw_tool_calc_distance_square:
 * @draw_tool: a #GimpDrawTool
 * @display:   a #GimpDisplay
 * @x1:        start point X in image coordinates
 * @y1:        start point Y in image coordinates
 * @x2:        end point X in image coordinates
 * @y2:        end point Y in image coordinates
 *
 * This function is more effective than gimp_draw_tool_calc_distance()
 * as it doesn't perform a sqrt(). Use this if you just need to compare
 * distances.
 *
 * Returns: the square of the distance between the given points in
Michael Natterer's avatar
Michael Natterer committed
315
 *          display coordinates
316 317 318 319 320 321 322 323
 **/
gdouble
gimp_draw_tool_calc_distance_square (GimpDrawTool *draw_tool,
                                     GimpDisplay  *display,
                                     gdouble       x1,
                                     gdouble       y1,
                                     gdouble       x2,
                                     gdouble       y2)
324
{
325 326 327
  GimpDisplayShell *shell;
  gdouble           tx1, ty1;
  gdouble           tx2, ty2;
328 329

  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), 0.0);
330
  g_return_val_if_fail (GIMP_IS_DISPLAY (display), 0.0);
331

332
  shell = gimp_display_get_shell (display);
333

334 335
  gimp_display_shell_transform_xy_f (shell, x1, y1, &tx1, &ty1);
  gimp_display_shell_transform_xy_f (shell, x2, y2, &tx2, &ty2);
336

337
  return SQR (tx2 - tx1) + SQR (ty2 - ty1);
338 339
}

340 341 342 343
void
gimp_draw_tool_add_item (GimpDrawTool   *draw_tool,
                         GimpCanvasItem *item)
{
344 345
  GimpCanvasGroup *group;

346
  g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
347
  g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
348 349

  if (! draw_tool->item)
350
    draw_tool->item = gimp_canvas_group_new (gimp_display_get_shell (draw_tool->display));
351

352 353 354 355 356 357
  group = GIMP_CANVAS_GROUP (draw_tool->item);

  if (draw_tool->group_stack)
    group = draw_tool->group_stack->data;

  gimp_canvas_group_add_item (group, item);
358 359
}

360 361 362 363 364 365 366 367 368 369 370
void
gimp_draw_tool_remove_item (GimpDrawTool   *draw_tool,
                            GimpCanvasItem *item)
{
  g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
  g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
  g_return_if_fail (draw_tool->item != NULL);

  gimp_canvas_group_remove_item (GIMP_CANVAS_GROUP (draw_tool->item), item);
}

371
GimpCanvasGroup *
372 373 374 375 376 377 378 379 380 381 382 383
gimp_draw_tool_add_stroke_group (GimpDrawTool *draw_tool)
{
  GimpCanvasItem *item;

  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);

  item = gimp_canvas_group_new (gimp_display_get_shell (draw_tool->display));
  gimp_canvas_group_set_group_stroking (GIMP_CANVAS_GROUP (item), TRUE);

  gimp_draw_tool_add_item (draw_tool, item);
  g_object_unref (item);

384
  return GIMP_CANVAS_GROUP (item);
385 386
}

387
GimpCanvasGroup *
388 389 390 391 392 393 394 395 396 397 398 399
gimp_draw_tool_add_fill_group (GimpDrawTool *draw_tool)
{
  GimpCanvasItem *item;

  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);

  item = gimp_canvas_group_new (gimp_display_get_shell (draw_tool->display));
  gimp_canvas_group_set_group_filling (GIMP_CANVAS_GROUP (item), TRUE);

  gimp_draw_tool_add_item (draw_tool, item);
  g_object_unref (item);

400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
  return GIMP_CANVAS_GROUP (item);
}

void
gimp_draw_tool_push_group (GimpDrawTool    *draw_tool,
                           GimpCanvasGroup *group)
{
  g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
  g_return_if_fail (GIMP_IS_CANVAS_GROUP (group));

  draw_tool->group_stack = g_list_prepend (draw_tool->group_stack, group);
}

void
gimp_draw_tool_pop_group (GimpDrawTool *draw_tool)
{
  g_return_if_fail (GIMP_IS_DRAW_TOOL (draw_tool));
  g_return_if_fail (draw_tool->group_stack != NULL);

  draw_tool->group_stack = g_list_remove (draw_tool->group_stack,
                                          draw_tool->group_stack->data);
421 422
}

423
/**
424
 * gimp_draw_tool_add_line:
425 426 427
 * @draw_tool:   the #GimpDrawTool
 * @x1:          start point X in image coordinates
 * @y1:          start point Y in image coordinates
428 429
 * @x2:          end point X in image coordinates
 * @y2:          end point Y in image coordinates
430 431 432 433 434
 *
 * This function takes image space coordinates and transforms them to
 * screen window coordinates, then draws a line between the resulting
 * coordindates.
 **/
435
GimpCanvasItem *
436 437 438 439 440
gimp_draw_tool_add_line (GimpDrawTool *draw_tool,
                         gdouble       x1,
                         gdouble       y1,
                         gdouble       x2,
                         gdouble       y2)
441
{
442
  GimpCanvasItem *item;
443

444
  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
445

446 447
  item = gimp_canvas_line_new (gimp_display_get_shell (draw_tool->display),
                               x1, y1, x2, y2);
448

449 450
  gimp_draw_tool_add_item (draw_tool, item);
  g_object_unref (item);
451 452

  return item;
453
}
454

455
/**
456
 * gimp_draw_tool_add_guide:
457 458 459 460 461 462
 * @draw_tool:   the #GimpDrawTool
 * @orientation: the orientation of the guide line
 * @position:    the position of the guide line in image coordinates
 *
 * This function draws a guide line across the canvas.
 **/
463
GimpCanvasItem *
464 465
gimp_draw_tool_add_guide (GimpDrawTool        *draw_tool,
                          GimpOrientationType  orientation,
466 467
                          gint                 position,
                          gboolean             guide_style)
468
{
469
  GimpCanvasItem *item;
470

471
  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
472

473
  item = gimp_canvas_guide_new (gimp_display_get_shell (draw_tool->display),
474
                                orientation, position, guide_style);
475

476 477
  gimp_draw_tool_add_item (draw_tool, item);
  g_object_unref (item);
478 479

  return item;
480 481
}

482
/**
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
 * gimp_draw_tool_add_crosshair:
 * @draw_tool:  the #GimpDrawTool
 * @position_x: the position of the vertical guide line in image coordinates
 * @position_y: the position of the horizontal guide line in image coordinates
 *
 * This function draws two crossing guide lines across the canvas.
 **/
GimpCanvasItem *
gimp_draw_tool_add_crosshair (GimpDrawTool *draw_tool,
                              gint          position_x,
                              gint          position_y)
{
  GimpCanvasGroup *group;

  group = gimp_draw_tool_add_stroke_group (draw_tool);

  gimp_draw_tool_push_group (draw_tool, group);
  gimp_draw_tool_add_guide (draw_tool,
                            GIMP_ORIENTATION_VERTICAL, position_x, FALSE);
  gimp_draw_tool_add_guide (draw_tool,
                            GIMP_ORIENTATION_HORIZONTAL, position_y, FALSE);
  gimp_draw_tool_pop_group (draw_tool);

  return GIMP_CANVAS_ITEM (group);
}

/**
 * gimp_draw_tool_add_sample_point:
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
 * @draw_tool: the #GimpDrawTool
 * @x:         X position of the sample point
 * @y:         Y position of the sample point
 * @index:     Index of the sample point
 *
 * This function draws a sample point
 **/
GimpCanvasItem *
gimp_draw_tool_add_sample_point (GimpDrawTool *draw_tool,
                                 gint          x,
                                 gint          y,
                                 gint          index)
{
  GimpCanvasItem *item;

  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);

528
  item = gimp_canvas_sample_point_new (gimp_display_get_shell (draw_tool->display),
529
                                       x, y, index, TRUE);
530 531 532 533 534 535 536

  gimp_draw_tool_add_item (draw_tool, item);
  g_object_unref (item);

  return item;
}

537
/**
538
 * gimp_draw_tool_add_rectangle:
539 540 541 542 543 544 545 546 547 548
 * @draw_tool:   the #GimpDrawTool
 * @filled:      whether to fill the rectangle
 * @x:           horizontal image coordinate
 * @y:           vertical image coordinate
 * @width:       width in image coordinates
 * @height:      height in image coordinates
 *
 * This function takes image space coordinates and transforms them to
 * screen window coordinates, then draws the resulting rectangle.
 **/
549
GimpCanvasItem *
550 551 552 553 554 555
gimp_draw_tool_add_rectangle (GimpDrawTool *draw_tool,
                              gboolean      filled,
                              gdouble       x,
                              gdouble       y,
                              gdouble       width,
                              gdouble       height)
556
{
557
  GimpCanvasItem *item;
558

559
  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
560

561 562
  item = gimp_canvas_rectangle_new (gimp_display_get_shell (draw_tool->display),
                                    x, y, width, height, filled);
563

564 565
  gimp_draw_tool_add_item (draw_tool, item);
  g_object_unref (item);
566 567

  return item;
568 569
}

570
GimpCanvasItem *
571 572 573 574 575 576 577 578
gimp_draw_tool_add_arc (GimpDrawTool *draw_tool,
                        gboolean      filled,
                        gdouble       x,
                        gdouble       y,
                        gdouble       width,
                        gdouble       height,
                        gdouble       start_angle,
                        gdouble       slice_angle)
579
{
580
  GimpCanvasItem *item;
581

582
  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
583

584 585
  item = gimp_canvas_arc_new (gimp_display_get_shell (draw_tool->display),
                              x + width  / 2.0,
586 587 588
                              y + height / 2.0,
                              width  / 2.0,
                              height / 2.0,
589 590
                              start_angle,
                              slice_angle,
591
                              filled);
592

593 594
  gimp_draw_tool_add_item (draw_tool, item);
  g_object_unref (item);
595 596

  return item;
597
}
598

599
GimpCanvasItem *
600 601 602 603 604 605 606
gimp_draw_tool_add_handle (GimpDrawTool   *draw_tool,
                           GimpHandleType  type,
                           gdouble         x,
                           gdouble         y,
                           gint            width,
                           gint            height,
                           GtkAnchorType   anchor)
607
{
608
  GimpCanvasItem *item;
609

610
  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
611

612 613
  item = gimp_canvas_handle_new (gimp_display_get_shell (draw_tool->display),
                                 type, anchor, x, y, width, height);
614

615 616
  gimp_draw_tool_add_item (draw_tool, item);
  g_object_unref (item);
617 618

  return item;
619 620
}

621
/**
622
 * gimp_draw_tool_add_corner:
623
 * @draw_tool:   the #GimpDrawTool
624
 * @highlight:
625
 * @put_outside: whether to put the handles on the outside of the rectangle
626 627 628 629 630 631 632 633 634 635 636 637
 * @x1:
 * @y1:
 * @x2:
 * @y2:
 * @width:       corner width
 * @height:      corner height
 * @anchor:      which corner to draw
 *
 * This function takes image space coordinates and transforms them to
 * screen window coordinates. It draws a corner into an already drawn
 * rectangle outline, taking care of not drawing over an already drawn line.
 **/
638
GimpCanvasItem *
639 640 641 642 643 644 645 646 647 648
gimp_draw_tool_add_corner (GimpDrawTool   *draw_tool,
                           gboolean        highlight,
                           gboolean        put_outside,
                           gdouble         x1,
                           gdouble         y1,
                           gdouble         x2,
                           gdouble         y2,
                           gint            width,
                           gint            height,
                           GtkAnchorType   anchor)
649
{
650
  GimpCanvasItem *item;
651

652
  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
653

654 655
  item = gimp_canvas_corner_new (gimp_display_get_shell (draw_tool->display),
                                 x1, y1, x2 - x1, y2 - y1,
656 657
                                 anchor, width, height, put_outside);
  gimp_canvas_item_set_highlight (item, highlight);
658

659 660
  gimp_draw_tool_add_item (draw_tool, item);
  g_object_unref (item);
661 662

  return item;
663 664
}

665
GimpCanvasItem *
666 667 668 669
gimp_draw_tool_add_lines (GimpDrawTool      *draw_tool,
                          const GimpVector2 *points,
                          gint               n_points,
                          gboolean           filled)
670
{
671
  GimpCanvasItem *item;
672

673
  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
674

675
  if (points == NULL || n_points < 2)
676
    return NULL;
677

678 679
  item = gimp_canvas_polygon_new (gimp_display_get_shell (draw_tool->display),
                                  points, n_points, filled);
680

681 682
  gimp_draw_tool_add_item (draw_tool, item);
  g_object_unref (item);
683 684

  return item;
685 686
}

687
GimpCanvasItem *
688 689 690 691
gimp_draw_tool_add_strokes (GimpDrawTool     *draw_tool,
                            const GimpCoords *points,
                            gint              n_points,
                            gboolean          filled)
692
{
693
  GimpCanvasItem *item;
694

695
  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
696

697
  if (points == NULL || n_points < 2)
698
    return NULL;
699

700 701
  item = gimp_canvas_polygon_new_from_coords (gimp_display_get_shell (draw_tool->display),
                                              points, n_points, filled);
702

703 704
  gimp_draw_tool_add_item (draw_tool, item);
  g_object_unref (item);
705 706

  return item;
707 708
}

709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
GimpCanvasItem *
gimp_draw_tool_add_pen (GimpDrawTool      *draw_tool,
                        const GimpVector2 *points,
                        gint               n_points,
                        GimpContext       *context,
                        GimpActiveColor    color,
                        gint               width)
{
  GimpCanvasItem *item;

  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);

  if (points == NULL || n_points < 2)
    return NULL;

  item = gimp_canvas_pen_new (gimp_display_get_shell (draw_tool->display),
                              points, n_points, context, color, width);

  gimp_draw_tool_add_item (draw_tool, item);
  g_object_unref (item);

  return item;
}

733
/**
734
 * gimp_draw_tool_add_boundary:
735 736 737 738 739 740 741 742 743 744 745
 * @draw_tool:    a #GimpDrawTool
 * @bound_segs:   the sorted brush outline
 * @n_bound_segs: the number of segments in @bound_segs
 * @offset_x:     x offset
 * @offset_y:     y offset
 *
 * Draw the boundary of the brush that @draw_tool uses. The boundary
 * should be sorted with sort_boundary(), and @n_bound_segs should
 * include the sentinel segments inserted by sort_boundary() that
 * indicate the end of connected segment sequences (groups) .
 */
746
GimpCanvasItem *
747 748 749 750 751
gimp_draw_tool_add_boundary (GimpDrawTool   *draw_tool,
                             const BoundSeg *bound_segs,
                             gint            n_bound_segs,
                             gdouble         offset_x,
                             gdouble         offset_y)
752
{
753
  GimpCanvasItem *item;
754

755 756 757
  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
  g_return_val_if_fail (n_bound_segs > 0, NULL);
  g_return_val_if_fail (bound_segs != NULL, NULL);
758

759 760
  item = gimp_canvas_boundary_new (gimp_display_get_shell (draw_tool->display),
                                   bound_segs, n_bound_segs,
761
                                   offset_x, offset_y);
762

763 764
  gimp_draw_tool_add_item (draw_tool, item);
  g_object_unref (item);
765 766

  return item;
767 768
}

769
GimpCanvasItem *
770 771 772
gimp_draw_tool_add_text_cursor (GimpDrawTool   *draw_tool,
                                PangoRectangle *cursor,
                                gboolean        overwrite)
773
{
774
  GimpCanvasItem *item;
775

776
  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), NULL);
777

778 779
  item = gimp_canvas_text_cursor_new (gimp_display_get_shell (draw_tool->display),
                                      cursor, overwrite);
780

781 782
  gimp_draw_tool_add_item (draw_tool, item);
  g_object_unref (item);
783 784

  return item;
785 786
}

787 788
gboolean
gimp_draw_tool_on_handle (GimpDrawTool   *draw_tool,
789
                          GimpDisplay    *display,
790 791 792 793 794 795 796
                          gdouble         x,
                          gdouble         y,
                          GimpHandleType  type,
                          gdouble         handle_x,
                          gdouble         handle_y,
                          gint            width,
                          gint            height,
797
                          GtkAnchorType   anchor)
798
{
799 800 801
  GimpDisplayShell *shell;
  gdouble           tx, ty;
  gdouble           handle_tx, handle_ty;
802

803
  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), FALSE);
804
  g_return_val_if_fail (GIMP_IS_DISPLAY (display), FALSE);
805

806
  shell = gimp_display_get_shell (display);
807 808 809

  gimp_display_shell_transform_xy_f (shell,
                                     x, y,
810
                                     &tx, &ty);
811 812
  gimp_display_shell_transform_xy_f (shell,
                                     handle_x, handle_y,
813
                                     &handle_tx, &handle_ty);
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836

  switch (type)
    {
    case GIMP_HANDLE_SQUARE:
    case GIMP_HANDLE_FILLED_SQUARE:
    case GIMP_HANDLE_CROSS:
      gimp_draw_tool_shift_to_north_west (handle_tx, handle_ty,
                                          width, height,
                                          anchor,
                                          &handle_tx, &handle_ty);

      return (tx == CLAMP (tx, handle_tx, handle_tx + width) &&
              ty == CLAMP (ty, handle_ty, handle_ty + height));

    case GIMP_HANDLE_CIRCLE:
    case GIMP_HANDLE_FILLED_CIRCLE:
      gimp_draw_tool_shift_to_center (handle_tx, handle_ty,
                                      width, height,
                                      anchor,
                                      &handle_tx, &handle_ty);

      /* FIXME */
      if (width != height)
837 838 839
        width = (width + height) / 2;

      width /= 2;
840 841 842 843

      return ((SQR (handle_tx - tx) + SQR (handle_ty - ty)) < SQR (width));

    default:
844
      g_warning ("%s: invalid handle type %d", G_STRFUNC, type);
845 846 847 848 849
      break;
    }

  return FALSE;
}
850

851
gboolean
Sven Neumann's avatar
Sven Neumann committed
852
gimp_draw_tool_on_vectors_handle (GimpDrawTool      *draw_tool,
853
                                  GimpDisplay       *display,
Sven Neumann's avatar
Sven Neumann committed
854 855 856 857 858 859 860 861
                                  GimpVectors       *vectors,
                                  const GimpCoords  *coord,
                                  gint               width,
                                  gint               height,
                                  GimpAnchorType     preferred,
                                  gboolean           exclusive,
                                  GimpAnchor       **ret_anchor,
                                  GimpStroke       **ret_stroke)
862 863 864 865 866 867 868 869 870 871
{
  GimpStroke *stroke       = NULL;
  GimpStroke *pref_stroke  = NULL;
  GimpAnchor *anchor       = NULL;
  GimpAnchor *pref_anchor  = NULL;
  gdouble     dx, dy;
  gdouble     pref_mindist = -1;
  gdouble     mindist      = -1;

  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), FALSE);
872
  g_return_val_if_fail (GIMP_IS_DISPLAY (display), FALSE);
873 874 875 876 877 878 879 880
  g_return_val_if_fail (GIMP_IS_VECTORS (vectors), FALSE);
  g_return_val_if_fail (coord != NULL, FALSE);

  if (ret_anchor) *ret_anchor = NULL;
  if (ret_stroke) *ret_stroke = NULL;

  while ((stroke = gimp_vectors_stroke_get_next (vectors, stroke)))
    {
881 882
      GList *anchor_list = gimp_stroke_get_draw_anchors (stroke);
      GList *list;
883

884 885
      anchor_list = g_list_concat (gimp_stroke_get_draw_anchors (stroke),
                                   gimp_stroke_get_draw_controls (stroke));
886

887
      for (list = anchor_list; list; list = g_list_next (list))
888
        {
889 890
          dx = coord->x - GIMP_ANCHOR (list->data)->position.x;
          dy = coord->y - GIMP_ANCHOR (list->data)->position.y;
891 892 893 894

          if (mindist < 0 || mindist > dx * dx + dy * dy)
            {
              mindist = dx * dx + dy * dy;
895 896
              anchor = GIMP_ANCHOR (list->data);

897 898 899 900 901
              if (ret_stroke)
                *ret_stroke = stroke;
            }

          if ((pref_mindist < 0 || pref_mindist > dx * dx + dy * dy) &&
902
              GIMP_ANCHOR (list->data)->type == preferred)
903 904
            {
              pref_mindist = dx * dx + dy * dy;
905
              pref_anchor = GIMP_ANCHOR (list->data);
906 907 908 909 910 911 912 913 914
              pref_stroke = stroke;
            }
        }

      g_list_free (anchor_list);
    }

  /* If the data passed into ret_anchor is a preferred anchor, return it. */
  if (ret_anchor && *ret_anchor &&
915
      gimp_draw_tool_on_handle (draw_tool, display,
916 917 918 919 920 921
                                coord->x,
                                coord->y,
                                GIMP_HANDLE_CIRCLE,
                                (*ret_anchor)->position.x,
                                (*ret_anchor)->position.y,
                                width, height,
922
                                GTK_ANCHOR_CENTER) &&
923 924 925 926 927 928 929
      (*ret_anchor)->type == preferred)
    {
      if (ret_stroke) *ret_stroke = pref_stroke;

      return TRUE;
    }

930
  if (pref_anchor && gimp_draw_tool_on_handle (draw_tool, display,
931 932 933 934 935 936
                                               coord->x,
                                               coord->y,
                                               GIMP_HANDLE_CIRCLE,
                                               pref_anchor->position.x,
                                               pref_anchor->position.y,
                                               width, height,
937
                                               GTK_ANCHOR_CENTER))
938 939 940 941 942 943
    {
      if (ret_anchor) *ret_anchor = pref_anchor;
      if (ret_stroke) *ret_stroke = pref_stroke;

      return TRUE;
    }
944
  else if (!exclusive && anchor &&
945
           gimp_draw_tool_on_handle (draw_tool, display,
946 947 948 949 950 951
                                     coord->x,
                                     coord->y,
                                     GIMP_HANDLE_CIRCLE,
                                     anchor->position.x,
                                     anchor->position.y,
                                     width, height,
952
                                     GTK_ANCHOR_CENTER))
953 954 955 956 957 958 959 960
    {
      if (ret_anchor)
        *ret_anchor = anchor;

      /* *ret_stroke already set correctly. */
      return TRUE;
    }

961 962 963 964
  if (ret_anchor)
    *ret_anchor = NULL;
  if (ret_stroke)
    *ret_stroke = NULL;
965

966 967 968 969
  return FALSE;
}

gboolean
Sven Neumann's avatar
Sven Neumann committed
970
gimp_draw_tool_on_vectors_curve (GimpDrawTool      *draw_tool,
971
                                 GimpDisplay       *display,
Sven Neumann's avatar
Sven Neumann committed
972 973 974 975 976 977 978 979 980
                                 GimpVectors       *vectors,
                                 const GimpCoords  *coord,
                                 gint               width,
                                 gint               height,
                                 GimpCoords        *ret_coords,
                                 gdouble           *ret_pos,
                                 GimpAnchor       **ret_segment_start,
                                 GimpAnchor       **ret_segment_end,
                                 GimpStroke       **ret_stroke)
981 982 983
{
  GimpStroke *stroke = NULL;
  GimpAnchor *segment_start;
984
  GimpAnchor *segment_end;
985 986
  GimpCoords  min_coords = GIMP_COORDS_DEFAULT_VALUES;
  GimpCoords  cur_coords;
987 988 989
  gdouble     min_dist, cur_dist, cur_pos;

  g_return_val_if_fail (GIMP_IS_DRAW_TOOL (draw_tool), FALSE);
990
  g_return_val_if_fail (GIMP_IS_DISPLAY (display), FALSE);
991 992 993 994
  g_return_val_if_fail (GIMP_IS_VECTORS (vectors), FALSE);
  g_return_val_if_fail (coord != NULL, FALSE);

  if (ret_coords)        *ret_coords        = *coord;
995
  if (ret_pos)           *ret_pos           = -1.0;
996
  if (ret_segment_start) *ret_segment_start = NULL;
997
  if (ret_segment_start) *ret_segment_end   = NULL;