gimppainttool.c 25.4 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
Elliot Lee's avatar
Elliot Lee committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * 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
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
17
 */
Sven Neumann's avatar
Sven Neumann committed
18

19 20
#include "config.h"

21
#include <gegl.h>
22
#include <gtk/gtk.h>
Sven Neumann's avatar
Sven Neumann committed
23

24 25
#include "libgimpmath/gimpmath.h"

26
#include "tools-types.h"
Sven Neumann's avatar
Sven Neumann committed
27

Michael Natterer's avatar
Michael Natterer committed
28
#include "core/gimp.h"
29 30
#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
31
#include "core/gimppaintinfo.h"
Michael Natterer's avatar
Michael Natterer committed
32
#include "core/gimpprojection.h"
33
#include "core/gimptoolinfo.h"
34
#include "core/gimpunit.h"
35

36
#include "paint/gimppaintcore.h"
37
#include "paint/gimppaintoptions.h"
38

39
#include "widgets/gimpdevices.h"
40
#include "widgets/gimpwidgets-utils.h"
41

42
#include "display/gimpdisplay.h"
Michael Natterer's avatar
Michael Natterer committed
43
#include "display/gimpdisplayshell.h"
44

Sven Neumann's avatar
Sven Neumann committed
45
#include "gimpcoloroptions.h"
46
#include "gimppainttool.h"
47
#include "gimptoolcontrol.h"
48
#include "tools-utils.h"
49

50
#include "gimp-intl.h"
51

52

53
#define HANDLE_SIZE    15
54
#define STATUSBAR_SIZE 200
Elliot Lee's avatar
Elliot Lee committed
55

56

57 58
static GObject * gimp_paint_tool_constructor (GType                  type,
                                              guint                  n_params,
59
                                              GObjectConstructParam *params);
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
static void   gimp_paint_tool_finalize       (GObject               *object);

static void   gimp_paint_tool_control        (GimpTool              *tool,
                                              GimpToolAction         action,
                                              GimpDisplay           *display);
static void   gimp_paint_tool_button_press   (GimpTool              *tool,
                                              GimpCoords            *coords,
                                              guint32                time,
                                              GdkModifierType        state,
                                              GimpDisplay           *display);
static void   gimp_paint_tool_button_release (GimpTool              *tool,
                                              GimpCoords            *coords,
                                              guint32                time,
                                              GdkModifierType        state,
                                              GimpButtonReleaseType  release_type,
                                              GimpDisplay           *display);
static void   gimp_paint_tool_motion         (GimpTool              *tool,
                                              GimpCoords            *coords,
                                              guint32                time,
                                              GdkModifierType        state,
                                              GimpDisplay           *display);
static void   gimp_paint_tool_modifier_key   (GimpTool              *tool,
                                              GdkModifierType        key,
                                              gboolean               press,
                                              GdkModifierType        state,
                                              GimpDisplay           *display);
static void   gimp_paint_tool_oper_update    (GimpTool              *tool,
                                              GimpCoords            *coords,
                                              GdkModifierType        state,
                                              gboolean               proximity,
                                              GimpDisplay           *display);

static void   gimp_paint_tool_draw           (GimpDrawTool          *draw_tool);
93

94 95 96 97
static void   gimp_paint_tool_hard_notify    (GimpPaintOptions      *options,
                                              const GParamSpec      *pspec,
                                              GimpTool              *tool);

Elliot Lee's avatar
Elliot Lee committed
98

99
G_DEFINE_TYPE (GimpPaintTool, gimp_paint_tool, GIMP_TYPE_COLOR_TOOL)
100

101
#define parent_class gimp_paint_tool_parent_class
102 103


104 105
static void
gimp_paint_tool_class_init (GimpPaintToolClass *klass)
106
{
107 108 109
  GObjectClass      *object_class    = G_OBJECT_CLASS (klass);
  GimpToolClass     *tool_class      = GIMP_TOOL_CLASS (klass);
  GimpDrawToolClass *draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass);
110

111
  object_class->constructor  = gimp_paint_tool_constructor;
112 113
  object_class->finalize     = gimp_paint_tool_finalize;

114
  tool_class->control        = gimp_paint_tool_control;
115 116 117
  tool_class->button_press   = gimp_paint_tool_button_press;
  tool_class->button_release = gimp_paint_tool_button_release;
  tool_class->motion         = gimp_paint_tool_motion;
Sven Neumann's avatar
Sven Neumann committed
118 119
  tool_class->modifier_key   = gimp_paint_tool_modifier_key;
  tool_class->oper_update    = gimp_paint_tool_oper_update;
120 121

  draw_tool_class->draw      = gimp_paint_tool_draw;
122
}
Elliot Lee's avatar
Elliot Lee committed
123

124
static void
125
gimp_paint_tool_init (GimpPaintTool *paint_tool)
126
{
Sven Neumann's avatar
Sven Neumann committed
127
  GimpTool *tool = GIMP_TOOL (paint_tool);
128

129 130
  gimp_tool_control_set_motion_mode    (tool->control, GIMP_MOTION_MODE_EXACT);
  gimp_tool_control_set_scroll_lock    (tool->control, TRUE);
131 132
  gimp_tool_control_set_action_value_1 (tool->control,
                                        "context/context-opacity-set");
Michael Natterer's avatar
Michael Natterer committed
133

134 135
  paint_tool->pick_colors = FALSE;
  paint_tool->draw_line   = FALSE;
136

137 138
  paint_tool->status      = _("Click to paint");
  paint_tool->status_line = _("Click to draw the line");
139 140
  paint_tool->status_ctrl = _("%s to pick a color");

141
  /*  Paint tools benefit most from strong smoothing on coordinates  */
142
  tool->max_coord_smooth  = 0.80;
143

144 145 146 147 148 149 150 151
  paint_tool->core        = NULL;
}

static GObject *
gimp_paint_tool_constructor (GType                  type,
                             guint                  n_params,
                             GObjectConstructParam *params)
{
152 153 154 155 156
  GObject          *object;
  GimpTool         *tool;
  GimpPaintInfo    *paint_info;
  GimpPaintTool    *paint_tool;
  GimpPaintOptions *options;
157 158 159 160 161

  object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);

  tool       = GIMP_TOOL (object);
  paint_tool = GIMP_PAINT_TOOL (object);
162
  options    = GIMP_PAINT_TOOL_GET_OPTIONS (tool);
163 164

  g_assert (GIMP_IS_TOOL_INFO (tool->tool_info));
165
  g_assert (GIMP_IS_PAINT_INFO (tool->tool_info->paint_info));
166

167 168 169 170 171 172
  paint_info = tool->tool_info->paint_info;

  g_assert (g_type_is_a (paint_info->paint_type, GIMP_TYPE_PAINT_CORE));

  paint_tool->core = g_object_new (paint_info->paint_type,
                                   "undo-desc", paint_info->blurb,
173 174
                                   NULL);

175 176 177 178 179 180
  g_signal_connect_object (options, "notify::hard",
                           G_CALLBACK (gimp_paint_tool_hard_notify),
                           tool, 0);

  gimp_paint_tool_hard_notify (options, NULL, tool);

181
  return object;
182 183 184 185 186
}

static void
gimp_paint_tool_finalize (GObject *object)
{
Sven Neumann's avatar
Sven Neumann committed
187
  GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (object);
188

189
  if (paint_tool->core)
190
    {
191
      g_object_unref (paint_tool->core);
192
      paint_tool->core = NULL;
193 194 195
    }

  G_OBJECT_CLASS (parent_class)->finalize (object);
196
}
Elliot Lee's avatar
Elliot Lee committed
197

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
/**
 * gimp_paint_tool_enable_color_picker:
 * @tool: a #GimpPaintTool
 * @mode: the #GimpColorPickMode to set
 *
 * This is a convenience function used from the init method of paint
 * tools that want the color picking functionality. The @mode that is
 * set here is used to decide what cursor modifier to draw and if the
 * picked color goes to the foreground or background color.
 **/
void
gimp_paint_tool_enable_color_picker (GimpPaintTool     *tool,
                                     GimpColorPickMode  mode)
{
  g_return_if_fail (GIMP_IS_PAINT_TOOL (tool));

  tool->pick_colors = TRUE;

  GIMP_COLOR_TOOL (tool)->pick_mode = mode;
}

219
static void
220
gimp_paint_tool_control (GimpTool       *tool,
221 222
                         GimpToolAction  action,
                         GimpDisplay    *display)
223
{
224
  GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
225
  GimpDrawable  *drawable   = gimp_image_get_active_drawable (display->image);
226 227

  switch (action)
228
    {
229 230 231 232 233
    case GIMP_TOOL_ACTION_PAUSE:
    case GIMP_TOOL_ACTION_RESUME:
      break;

    case GIMP_TOOL_ACTION_HALT:
234 235
      gimp_paint_core_paint (paint_tool->core,
                             drawable,
236
                             GIMP_PAINT_TOOL_GET_OPTIONS (tool),
237
                             GIMP_PAINT_STATE_FINISH, 0);
238
      gimp_paint_core_cleanup (paint_tool->core);
239
      break;
240 241
    }

242
  GIMP_TOOL_CLASS (parent_class)->control (tool, action, display);
243
}
244

245 246
/**
 * gimp_paint_tool_round_line:
247 248 249
 * @core:          the #GimpPaintCore
 * @center_pixels: push coordinates to pixel centers?
 * @state:         the modifier state
250 251
 *
 * Adjusts core->last_coords and core_cur_coords in preparation to
252 253 254
 * drawing a straight line. If @center_pixels is TRUE the endpoints
 * get pushed to the center of the pixels. This avoids artefacts
 * for e.g. the hard mode. The rounding of the slope to 15 degree
255 256 257 258 259 260
 * steps if ctrl is pressed happens, as does rounding the start and
 * end coordinates (which may be fractional in high zoom modes) to
 * the center of pixels.
 **/
static void
gimp_paint_tool_round_line (GimpPaintCore   *core,
261
                            gboolean         center_pixels,
262 263
                            GdkModifierType  state)
{
264 265 266 267 268 269 270
  if (center_pixels)
    {
      core->last_coords.x = floor (core->last_coords.x) + 0.5;
      core->last_coords.y = floor (core->last_coords.y) + 0.5;
      core->cur_coords.x  = floor (core->cur_coords.x ) + 0.5;
      core->cur_coords.y  = floor (core->cur_coords.y ) + 0.5;
    }
271

272
  if (state & GDK_CONTROL_MASK)
273
    gimp_tool_motion_constrain (core->last_coords.x, core->last_coords.y,
274
                                &core->cur_coords.x, &core->cur_coords.y,
275
                                GIMP_TOOL_CONSTRAIN_15_DEGREES);
276 277
}

278
static void
279 280 281
gimp_paint_tool_button_press (GimpTool        *tool,
                              GimpCoords      *coords,
                              guint32          time,
282 283
                              GdkModifierType  state,
                              GimpDisplay     *display)
Elliot Lee's avatar
Elliot Lee committed
284
{
285 286 287
  GimpDrawTool     *draw_tool     = GIMP_DRAW_TOOL (tool);
  GimpPaintTool    *paint_tool    = GIMP_PAINT_TOOL (tool);
  GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (tool);
288
  GimpPaintCore    *core          = paint_tool->core;
289 290
  GimpDrawable     *drawable;
  GimpCoords        curr_coords;
291
  gint              off_x, off_y;
292
  GError           *error = NULL;
293

294 295 296 297 298 299
  if (gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)))
    {
      GIMP_TOOL_CLASS (parent_class)->button_press (tool, coords, time, state,
                                                    display);
      return;
    }
300

301
  drawable = gimp_image_get_active_drawable (display->image);
Elliot Lee's avatar
Elliot Lee committed
302

303 304
  curr_coords = *coords;

305
  gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y);
306

307 308
  curr_coords.x -= off_x;
  curr_coords.y -= off_y;
309

310 311 312
  if (gimp_draw_tool_is_active (draw_tool))
    gimp_draw_tool_stop (draw_tool);

313 314 315
  if (tool->display          &&
      tool->display != display &&
      tool->display->image == display->image)
316 317 318 319 320 321 322
    {
      /*  if this is a different display, but the same image, HACK around
       *  in tool internals AFTER stopping the current draw_tool, so
       *  straight line drawing works across different views of the
       *  same image.
       */

323
      tool->display = display;
324 325
    }

326 327 328
  if (! gimp_paint_core_start (core, drawable, paint_options, &curr_coords,
                               &error))
    {
329
      gimp_tool_message (tool, display, error->message);
330 331 332
      g_clear_error (&error);
      return;
    }
Elliot Lee's avatar
Elliot Lee committed
333

334
  if ((display != tool->display) || ! paint_tool->draw_line)
Elliot Lee's avatar
Elliot Lee committed
335
    {
336 337
      /*  if this is a new image, reinit the core vals  */

338 339
      core->start_coords = core->cur_coords;
      core->last_coords  = core->cur_coords;
340 341 342

      core->distance     = 0.0;
      core->pixel_dist   = 0.0;
Elliot Lee's avatar
Elliot Lee committed
343
    }
344
  else if (paint_tool->draw_line)
Elliot Lee's avatar
Elliot Lee committed
345
    {
346 347 348
      /*  If shift is down and this is not the first paint
       *  stroke, then draw a line from the last coords to the pointer
       */
349
      gboolean hard;
350 351 352

      hard = (gimp_paint_options_get_brush_mode (paint_options) ==
              GIMP_BRUSH_HARD);
353 354 355

      core->start_coords = core->last_coords;

356
      gimp_paint_tool_round_line (core, hard, state);
Elliot Lee's avatar
Elliot Lee committed
357 358
    }

359 360 361
  /*  chain up to activate the tool  */
  GIMP_TOOL_CLASS (parent_class)->button_press (tool, coords, time, state,
                                                display);
Elliot Lee's avatar
Elliot Lee committed
362

363
  /*  pause the current selection  */
364
  gimp_image_selection_control (display->image, GIMP_SELECTION_PAUSE);
Elliot Lee's avatar
Elliot Lee committed
365 366

  /*  Let the specific painting function initialize itself  */
367 368
  gimp_paint_core_paint (core, drawable, paint_options,
                         GIMP_PAINT_STATE_INIT, time);
Elliot Lee's avatar
Elliot Lee committed
369 370

  /*  Paint to the image  */
371
  if (paint_tool->draw_line)
Elliot Lee's avatar
Elliot Lee committed
372
    {
373
      gimp_paint_core_interpolate (core, drawable, paint_options, time);
Elliot Lee's avatar
Elliot Lee committed
374 375
    }
  else
376
    {
377 378
      gimp_paint_core_paint (core, drawable, paint_options,
                             GIMP_PAINT_STATE_MOTION, time);
379
    }
Sven Neumann's avatar
Sven Neumann committed
380

381
  gimp_projection_flush_now (gimp_image_get_projection (display->image));
382
  gimp_display_flush_now (display);
Sven Neumann's avatar
Sven Neumann committed
383

384
  gimp_draw_tool_start (draw_tool, display);
Elliot Lee's avatar
Elliot Lee committed
385 386
}

387
static void
388 389 390 391 392 393
gimp_paint_tool_button_release (GimpTool              *tool,
                                GimpCoords            *coords,
                                guint32                time,
                                GdkModifierType        state,
                                GimpButtonReleaseType  release_type,
                                GimpDisplay           *display)
Elliot Lee's avatar
Elliot Lee committed
394
{
395 396
  GimpPaintTool    *paint_tool    = GIMP_PAINT_TOOL (tool);
  GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (tool);
397
  GimpPaintCore    *core          = paint_tool->core;
398
  GimpDrawable     *drawable;
Elliot Lee's avatar
Elliot Lee committed
399

400 401 402
  if (gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)))
    {
      GIMP_TOOL_CLASS (parent_class)->button_release (tool, coords, time,
403 404
                                                      state, release_type,
                                                      display);
405 406
      return;
    }
407

408
  drawable = gimp_image_get_active_drawable (display->image);
Michael Natterer's avatar
Michael Natterer committed
409

410 411
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));

Elliot Lee's avatar
Elliot Lee committed
412
  /*  Let the specific painting function finish up  */
413 414
  gimp_paint_core_paint (core, drawable, paint_options,
                         GIMP_PAINT_STATE_FINISH, time);
Elliot Lee's avatar
Elliot Lee committed
415

416
  /*  resume the current selection  */
417
  gimp_image_selection_control (display->image, GIMP_SELECTION_RESUME);
418

Sven Neumann's avatar
Sven Neumann committed
419
  /*  chain up to halt the tool */
420
  GIMP_TOOL_CLASS (parent_class)->button_release (tool, coords, time, state,
421
                                                  release_type, display);
Elliot Lee's avatar
Elliot Lee committed
422

423
  if (release_type == GIMP_BUTTON_RELEASE_CANCEL)
424 425
    gimp_paint_core_cancel (core, drawable);
  else
426
    gimp_paint_core_finish (core, drawable, TRUE);
427

428
  gimp_image_flush (display->image);
429 430

  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Elliot Lee's avatar
Elliot Lee committed
431 432
}

433
static void
434 435 436
gimp_paint_tool_motion (GimpTool        *tool,
                        GimpCoords      *coords,
                        guint32          time,
437 438
                        GdkModifierType  state,
                        GimpDisplay     *display)
Elliot Lee's avatar
Elliot Lee committed
439
{
440 441
  GimpPaintTool    *paint_tool    = GIMP_PAINT_TOOL (tool);
  GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (tool);
442
  GimpPaintCore    *core          = paint_tool->core;
443
  GimpDrawable     *drawable;
444
  gint              off_x, off_y;
Elliot Lee's avatar
Elliot Lee committed
445

446 447 448 449 450 451
  if (gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)))
    {
      GIMP_TOOL_CLASS (parent_class)->motion (tool, coords, time, state,
                                              display);
      return;
    }
452

453
  drawable = gimp_image_get_active_drawable (display->image);
Michael Natterer's avatar
Michael Natterer committed
454

455
  core->cur_coords = *coords;
456

457
  gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y);
458

459 460
  core->cur_coords.x -= off_x;
  core->cur_coords.y -= off_y;
461

462 463 464 465 466
  GIMP_TOOL_CLASS (parent_class)->motion (tool, coords, time, state, display);

  /*  don't paint while the Shift key is pressed for line drawing  */
  if (paint_tool->draw_line)
    return;
467

468
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Sven Neumann's avatar
Sven Neumann committed
469

470
  gimp_paint_core_interpolate (core, drawable, paint_options, time);
471

472
  gimp_projection_flush_now (gimp_image_get_projection (display->image));
473
  gimp_display_flush_now (display);
Sven Neumann's avatar
Sven Neumann committed
474

475
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Elliot Lee's avatar
Elliot Lee committed
476 477
}

478
static void
Sven Neumann's avatar
Sven Neumann committed
479 480 481 482
gimp_paint_tool_modifier_key (GimpTool        *tool,
                              GdkModifierType  key,
                              gboolean         press,
                              GdkModifierType  state,
483
                              GimpDisplay     *display)
Sven Neumann's avatar
Sven Neumann committed
484
{
485 486
  GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
  GimpDrawTool  *draw_tool  = GIMP_DRAW_TOOL (tool);
487

Sven Neumann's avatar
Sven Neumann committed
488 489 490
  if (key != GDK_CONTROL_MASK)
    return;

491
  if (paint_tool->pick_colors && ! paint_tool->draw_line)
Sven Neumann's avatar
Sven Neumann committed
492 493 494
    {
      if (press)
        {
495 496
          GimpToolInfo *info = gimp_get_tool_info (display->image->gimp,
                                                   "gimp-color-picker-tool");
497

498 499 500 501 502 503 504
          if (GIMP_IS_TOOL_INFO (info))
            {
              if (gimp_draw_tool_is_active (draw_tool))
                gimp_draw_tool_stop (draw_tool);

              gimp_color_tool_enable (GIMP_COLOR_TOOL (tool),
                                      GIMP_COLOR_OPTIONS (info->tool_options));
505

506 507 508 509 510
              switch (GIMP_COLOR_TOOL (tool)->pick_mode)
                {
                case GIMP_COLOR_PICK_MODE_FOREGROUND:
                  gimp_tool_push_status (tool, display,
                                         _("Click in any image to pick the "
511
                                           "foreground color"));
512 513 514 515 516
                  break;

                case GIMP_COLOR_PICK_MODE_BACKGROUND:
                  gimp_tool_push_status (tool, display,
                                         _("Click in any image to pick the "
517
                                           "background color"));
518 519 520 521 522
                  break;

                default:
                  break;
                }
523
            }
Sven Neumann's avatar
Sven Neumann committed
524 525 526
        }
      else
        {
527
          if (gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)))
528 529 530 531
            {
              gimp_tool_pop_status (tool, display);
              gimp_color_tool_disable (GIMP_COLOR_TOOL (tool));
            }
Sven Neumann's avatar
Sven Neumann committed
532 533 534 535 536 537 538 539
        }
    }
}

static void
gimp_paint_tool_oper_update (GimpTool        *tool,
                             GimpCoords      *coords,
                             GdkModifierType  state,
540
                             gboolean         proximity,
541
                             GimpDisplay     *display)
Elliot Lee's avatar
Elliot Lee committed
542
{
543 544 545
  GimpPaintTool    *paint_tool    = GIMP_PAINT_TOOL (tool);
  GimpDrawTool     *draw_tool     = GIMP_DRAW_TOOL (tool);
  GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (tool);
546 547
  GimpPaintCore    *core          = paint_tool->core;
  GimpDisplayShell *shell         = GIMP_DISPLAY_SHELL (display->shell);
548
  GimpDrawable     *drawable;
Elliot Lee's avatar
Elliot Lee committed
549

550
  if (gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)))
551
    {
552
      GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state,
553
                                                   proximity, display);
554 555 556 557
      return;
    }

  if (gimp_draw_tool_is_active (draw_tool))
558
    gimp_draw_tool_stop (draw_tool);
559

560
  gimp_tool_pop_status (tool, display);
561

562
  if (tool->display            &&
563 564
      tool->display != display &&
      tool->display->image == display->image)
565 566 567 568 569 570 571
    {
      /*  if this is a different display, but the same image, HACK around
       *  in tool internals AFTER stopping the current draw_tool, so
       *  straight line drawing works across different views of the
       *  same image.
       */

572
      tool->display = display;
573 574
    }

575
  drawable = gimp_image_get_active_drawable (display->image);
576

577
  if (drawable && proximity)
578
    {
579
      if (display == tool->display && (state & GDK_SHIFT_MASK))
580
        {
581
          /*  If shift is down and this is not the first paint stroke,
582
           *  draw a line.
583 584
           */

585 586 587 588
          gchar    *status_help;
          gdouble   dx, dy, dist;
          gint      off_x, off_y;
          gboolean  hard;
589

590
          core->cur_coords = *coords;
591

592
          gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y);
593

594 595
          core->cur_coords.x -= off_x;
          core->cur_coords.y -= off_y;
Sven Neumann's avatar
Sven Neumann committed
596

597 598
          hard = (gimp_paint_options_get_brush_mode (paint_options) ==
                  GIMP_BRUSH_HARD);
599
          gimp_paint_tool_round_line (core, hard, state);
600

601 602
          dx = core->cur_coords.x - core->last_coords.x;
          dy = core->cur_coords.y - core->last_coords.y;
603

604 605 606 607 608
          status_help = gimp_suggest_modifiers (paint_tool->status_line,
                                                GDK_CONTROL_MASK & ~state,
                                                NULL,
                                                _("%s for constrained angles"),
                                                NULL);
609

610
          /*  show distance in statusbar  */
611
          if (shell->unit == GIMP_UNIT_PIXEL)
612 613
            {
              dist = sqrt (SQR (dx) + SQR (dy));
614

615 616
              gimp_tool_push_status (tool, display, "%.1f %s.  %s",
                                     dist, _("pixels"), status_help);
617 618 619
            }
          else
            {
620
              GimpImage *image = display->image;
621 622
              gdouble    xres;
              gdouble    yres;
623
              gchar      format_str[64];
624

625 626
              gimp_image_get_resolution (image, &xres, &yres);

627
              g_snprintf (format_str, sizeof (format_str), "%%.%df %s.  %%s",
628 629
                          _gimp_unit_get_digits (image->gimp, shell->unit),
                          _gimp_unit_get_symbol (image->gimp, shell->unit));
630

631
              dist = (_gimp_unit_get_factor (image->gimp, shell->unit) *
632 633
                      sqrt (SQR (dx / xres) +
                            SQR (dy / yres)));
634

635 636
              gimp_tool_push_status (tool, display, format_str,
                                     dist, status_help);
637
            }
638

639
          g_free (status_help);
640

641 642 643 644
          paint_tool->draw_line = TRUE;
        }
      else
        {
645 646 647 648 649 650
          gchar           *status;
          GdkModifierType  modifiers = 0;

          /* HACK: A paint tool may set status_ctrl to NULL to indicate that
           * it ignores the Ctrl modifier (temporarily or permanently), so
           * it should not be suggested.  This is different from how
651 652
           * gimp_suggest_modifiers() would interpret this parameter.
           */
653 654
          if (paint_tool->status_ctrl != NULL)
            modifiers |= GDK_CONTROL_MASK;
655 656 657

          /* suggest drawing lines only after the first point is set
           */
658
          if (display == tool->display)
659 660 661 662 663 664 665
            modifiers |= GDK_SHIFT_MASK;

          status = gimp_suggest_modifiers (paint_tool->status,
                                           modifiers & ~state,
                                           _("%s for a straight line"),
                                           paint_tool->status_ctrl,
                                           NULL);
666 667
          gimp_tool_push_status (tool, display, status);
          g_free (status);
668

669 670 671
          paint_tool->draw_line = FALSE;
        }

672
      gimp_draw_tool_start (draw_tool, display);
673
    }
Michael Natterer's avatar
Michael Natterer committed
674

675
  GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state, proximity,
676
                                               display);
Elliot Lee's avatar
Elliot Lee committed
677 678
}

679 680
static void
gimp_paint_tool_draw (GimpDrawTool *draw_tool)
Elliot Lee's avatar
Elliot Lee committed
681
{
Sven Neumann's avatar
Sven Neumann committed
682
  if (! gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (draw_tool)))
683
    {
684 685
      GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (draw_tool);
      GimpPaintCore *core       = paint_tool->core;
686

687 688
      if (paint_tool->draw_line &&
          ! gimp_tool_control_is_active (GIMP_TOOL (draw_tool)->control))
689 690 691 692 693 694
        {
          /*  Draw start target  */
          gimp_draw_tool_draw_handle (draw_tool,
                                      GIMP_HANDLE_CROSS,
                                      core->last_coords.x,
                                      core->last_coords.y,
695 696
                                      HANDLE_SIZE,
                                      HANDLE_SIZE,
697 698 699 700 701 702 703 704
                                      GTK_ANCHOR_CENTER,
                                      TRUE);

          /*  Draw end target  */
          gimp_draw_tool_draw_handle (draw_tool,
                                      GIMP_HANDLE_CROSS,
                                      core->cur_coords.x,
                                      core->cur_coords.y,
705 706
                                      HANDLE_SIZE,
                                      HANDLE_SIZE,
707 708 709 710 711 712 713 714 715 716 717
                                      GTK_ANCHOR_CENTER,
                                      TRUE);

          /*  Draw the line between the start and end coords  */
          gimp_draw_tool_draw_line (draw_tool,
                                    core->last_coords.x,
                                    core->last_coords.y,
                                    core->cur_coords.x,
                                    core->cur_coords.y,
                                    TRUE);
        }
718
    }
Sven Neumann's avatar
Sven Neumann committed
719 720

  GIMP_DRAW_TOOL_CLASS (parent_class)->draw (draw_tool);
721
}
722 723 724 725 726 727 728 729 730 731 732

static void
gimp_paint_tool_hard_notify (GimpPaintOptions *options,
                             const GParamSpec *pspec,
                             GimpTool         *tool)
{
  gimp_tool_control_set_precision (tool->control,
                                   options->hard ?
                                   GIMP_CURSOR_PRECISION_PIXEL_CENTER :
                                   GIMP_CURSOR_PRECISION_SUBPIXEL);
}