1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2004-11-16
7 * Description : a widget to display an image with guides
8 *
9 * Copyright (C) 2004-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10 *
11 * This program is free software; you can redistribute it
12 * and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software Foundation;
14 * either version 2, or (at your option)
15 * any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * ============================================================ */
23
24 #include "imageguidewidget.h"
25
26 // Qt includes
27
28 #include <QRegion>
29 #include <QPainter>
30 #include <QPen>
31 #include <QTimer>
32 #include <QRect>
33 #include <QBrush>
34 #include <QFont>
35 #include <QFontMetrics>
36
37 // KDE includes
38
39 #include <klocalizedstring.h>
40
41 // Local includes
42
43 #include "dimg.h"
44 #include "digikam_debug.h"
45 #include "previewtoolbar.h"
46 #include "exposurecontainer.h"
47 #include "iccsettingscontainer.h"
48
49 namespace Digikam
50 {
51
52 static const KLocalizedString beforeLabel = ki18nc("Preview image (before filter has been applied)", "Before");
53 static const KLocalizedString afterLabel = ki18nc("Preview image (after filter has been applied)", "After");
54
55 class Q_DECL_HIDDEN ImageGuideWidget::Private
56 {
57 public:
58
Private()59 explicit Private()
60 : sixteenBit(false),
61 focus(false),
62 spotVisible(false),
63 onMouseMovePreviewToggled(true),
64 drawLineBetweenPoints(false),
65 drawingMask(false),
66 enableDrawMask(false),
67 eraseMask(false),
68 timerID(0),
69 guideMode(0),
70 guideSize(0),
71 flicker(0),
72 renderingPreviewMode(PreviewToolBar::NoPreviewMode),
73 penWidth(10),
74 pixmap(nullptr),
75 maskPixmap(nullptr),
76 previewPixmap(nullptr),
77 iface(nullptr)
78 {
79 }
80
81 bool sixteenBit;
82 bool focus;
83 bool spotVisible;
84 bool onMouseMovePreviewToggled;
85 bool drawLineBetweenPoints;
86 bool drawingMask;
87 bool enableDrawMask;
88 bool eraseMask;
89
90 int timerID;
91 int guideMode;
92 int guideSize;
93 int flicker;
94 int renderingPreviewMode;
95 int penWidth;
96
97 /// Current spot position in preview coordinates.
98 QPoint spot;
99 QPolygon selectedPoints;
100
101 QRect rect;
102
103 QColor guideColor;
104 QColor paintColor;
105 QColor bgColor;
106
107 QPixmap* pixmap;
108 QPixmap* maskPixmap;
109 QPixmap* previewPixmap;
110
111 QCursor maskCursor;
112
113 QPoint lastPoint;
114
115 ImageIface* iface;
116
117 DImg preview;
118 };
119
ImageGuideWidget(QWidget * const parent,bool spotVisible,int guideMode,const QColor & guideColor,int guideSize,bool blink,ImageIface::PreviewType type)120 ImageGuideWidget::ImageGuideWidget(QWidget* const parent,
121 bool spotVisible,
122 int guideMode,
123 const QColor& guideColor,
124 int guideSize,
125 bool blink, ImageIface::PreviewType type)
126 : QWidget(parent),
127 d(new Private)
128 {
129 int w = 480;
130 int h = 320;
131 d->spotVisible = spotVisible;
132 d->guideMode = guideMode;
133 d->guideColor = guideColor;
134 d->guideSize = guideSize;
135 d->bgColor = palette().color(QPalette::Base);
136
137 setMinimumSize(w, h);
138 setMouseTracking(true);
139 setAttribute(Qt::WA_DeleteOnClose);
140
141 d->iface = new ImageIface(QSize(w, h));
142 d->iface->setPreviewType(type);
143 d->preview = d->iface->preview();
144 d->preview.setIccProfile(d->iface->original() ? d->iface->original()->getIccProfile() : IccProfile());
145
146 d->pixmap = new QPixmap(w, h);
147 d->rect = QRect(w / 2 - d->preview.width() / 2, h / 2 - d->preview.height() / 2, d->preview.width(), d->preview.height());
148 d->maskPixmap = new QPixmap(d->rect.width(), d->rect.height());
149 d->previewPixmap = new QPixmap(d->rect.width(), d->rect.height());
150 d->maskPixmap->fill(QColor(0, 0, 0, 0));
151 d->previewPixmap->fill(QColor(0, 0, 0, 0));
152
153 d->paintColor.setRgb(255, 255, 255, 255);
154
155 d->lastPoint = QPoint(d->rect.x(), d->rect.y());
156
157 resetSpotPosition();
158 setSpotVisible(d->spotVisible, blink);
159 }
160
~ImageGuideWidget()161 ImageGuideWidget::~ImageGuideWidget()
162 {
163 delete d->iface;
164
165 if (d->timerID)
166 {
167 killTimer(d->timerID);
168 }
169
170 delete d->pixmap;
171 delete d->maskPixmap;
172 delete d->previewPixmap;
173 delete d;
174 }
175
imageIface() const176 ImageIface* ImageGuideWidget::imageIface() const
177 {
178 return d->iface;
179 }
180
setBackgroundColor(const QColor & bg)181 void ImageGuideWidget::setBackgroundColor(const QColor& bg)
182 {
183 d->bgColor = bg;
184 updatePreview();
185 }
186
ICCSettingsChanged()187 void ImageGuideWidget::ICCSettingsChanged()
188 {
189 updatePreview();
190 }
191
exposureSettingsChanged()192 void ImageGuideWidget::exposureSettingsChanged()
193 {
194 updatePreview();
195 }
196
resetSpotPosition()197 void ImageGuideWidget::resetSpotPosition()
198 {
199 d->spot.setX(d->preview.width() / 2);
200 d->spot.setY(d->preview.height() / 2);
201 updatePreview();
202 }
203
slotPreviewModeChanged(int mode)204 void ImageGuideWidget::slotPreviewModeChanged(int mode)
205 {
206 d->renderingPreviewMode = mode;
207 updatePreview();
208 }
209
previewMode() const210 int ImageGuideWidget::previewMode() const
211 {
212 return (d->renderingPreviewMode);
213 }
214
getSpotPosition() const215 QPoint ImageGuideWidget::getSpotPosition() const
216 {
217 return (QPoint((int)((float)d->spot.x() * (float)d->iface->originalSize().width() / (float)d->preview.width()),
218 (int)((float)d->spot.y() * (float)d->iface->originalSize().height() / (float)d->preview.height())));
219 }
220
getSpotColor(int getColorFrom) const221 DColor ImageGuideWidget::getSpotColor(int getColorFrom) const
222 {
223 if (getColorFrom == OriginalImage) // Get point color from full original image
224 {
225 return (d->iface->colorInfoFromOriginal(getSpotPosition()));
226 }
227 else if (getColorFrom == PreviewImage) // Get point color from full preview image
228 {
229 return (d->iface->colorInfoFromPreview(d->spot));
230 }
231
232 // In other cases, get point color from preview target image
233
234 return (d->iface->colorInfoFromTargetPreview(d->spot));
235 }
236
setSpotVisible(bool spotVisible,bool blink)237 void ImageGuideWidget::setSpotVisible(bool spotVisible, bool blink)
238 {
239 d->spotVisible = spotVisible;
240
241 if (blink)
242 {
243 if (d->spotVisible)
244 {
245 d->timerID = startTimer(800);
246 }
247 else
248 {
249 killTimer(d->timerID);
250 d->timerID = 0;
251 }
252 }
253
254 updatePreview();
255 }
256
setSpotVisibleNoUpdate(bool spotVisible)257 void ImageGuideWidget::setSpotVisibleNoUpdate(bool spotVisible)
258 {
259 d->spotVisible = spotVisible;
260 }
261
slotChangeGuideColor(const QColor & color)262 void ImageGuideWidget::slotChangeGuideColor(const QColor& color)
263 {
264 d->guideColor = color;
265 updatePreview();
266 }
267
slotChangeGuideSize(int size)268 void ImageGuideWidget::slotChangeGuideSize(int size)
269 {
270 d->guideSize = size;
271 updatePreview();
272 }
273
updatePreview()274 void ImageGuideWidget::updatePreview()
275 {
276 updatePixmap();
277 update();
278 }
279
updatePixmap()280 void ImageGuideWidget::updatePixmap()
281 {
282 QPainter p(d->pixmap);
283 p.setRenderHint(QPainter::Antialiasing, true);
284 p.setBackgroundMode(Qt::TransparentMode);
285
286 QString text;
287 p.setPen(QPen(Qt::red, 1));
288
289 d->pixmap->fill(d->bgColor);
290
291 if ((d->renderingPreviewMode == PreviewToolBar::PreviewOriginalImage) ||
292 ((d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) && !d->onMouseMovePreviewToggled))
293 {
294 p.drawPixmap(d->rect, *d->previewPixmap);
295 drawText(&p, QPoint(d->rect.x() + 20, d->rect.y() + 20), beforeLabel.toString());
296 }
297 else if ((d->renderingPreviewMode == PreviewToolBar::PreviewTargetImage) ||
298 (d->renderingPreviewMode == PreviewToolBar::NoPreviewMode) ||
299 ((d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) && d->onMouseMovePreviewToggled))
300 {
301 d->iface->paint(d->pixmap, d->rect, &p);
302
303 if ((d->renderingPreviewMode == PreviewToolBar::PreviewTargetImage) ||
304 (d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver))
305 {
306 drawText(&p, QPoint(d->rect.x() + 20, d->rect.y() + 20), afterLabel.toString());
307 }
308 }
309 else if ((d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVert) ||
310 (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVertCont))
311 {
312 if (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVert)
313 {
314 // Drawing original image.
315
316 p.drawPixmap(d->rect, *d->previewPixmap);
317
318 // Drawing target image under the original.
319
320 d->iface->paint(d->pixmap, QRect(d->rect.x() + d->rect.width() / 2, d->rect.y(), d->rect.width() / 2, d->rect.height()), &p);
321 }
322 else
323 {
324 // Drawing target image.
325
326 d->iface->paint(d->pixmap, d->rect, &p);
327
328 // Drawing original image under the target.
329
330 p.drawPixmap(d->rect.x(), d->rect.y(), *d->previewPixmap, 0, 0, d->rect.width() / 2, d->rect.height());
331 }
332
333 // Drawing information and others stuff.
334
335 p.fillRect(d->rect.right(), 0, width(), height(), palette().color(QPalette::Window));
336
337 p.setPen(QPen(Qt::white, 2, Qt::SolidLine));
338 p.drawLine(d->rect.x() + d->rect.width() / 2 - 1, d->rect.y(),
339 d->rect.x() + d->rect.width() / 2 - 1, d->rect.y() + d->rect.height());
340 p.setPen(QPen(Qt::red, 2, Qt::DotLine));
341 p.drawLine(d->rect.x() + d->rect.width() / 2 - 1, d->rect.y(),
342 d->rect.x() + d->rect.width() / 2 - 1, d->rect.y() + d->rect.height());
343
344 drawText(&p, QPoint(d->rect.x() + 20, d->rect.y() + 20), beforeLabel.toString());
345 drawText(&p, QPoint(d->rect.x() + d->rect.width() / 2 + 20, d->rect.y() + 20), afterLabel.toString());
346 }
347 else if ((d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorz) ||
348 (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorzCont))
349 {
350 if (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorz)
351 {
352 // Drawing original image.
353
354 p.drawPixmap(d->rect, *d->previewPixmap);
355
356 // Drawing target image under the original.
357
358 d->iface->paint(d->pixmap, QRect(d->rect.x(), d->rect.y() + d->rect.height() / 2, d->rect.width(), d->rect.height() / 2), &p);
359 }
360 else
361 {
362 // Drawing target image.
363
364 d->iface->paint(d->pixmap, d->rect, &p);
365
366 // Drawing original image under the target.
367
368 p.drawPixmap(d->rect.x(), d->rect.y(), *d->previewPixmap,
369 0, 0, d->rect.width(), d->rect.height() / 2);
370 }
371
372 p.fillRect(0, d->rect.bottom(), width(), height(), palette().color(QPalette::Window));
373
374 p.setPen(QPen(Qt::white, 2, Qt::SolidLine));
375 p.drawLine(d->rect.x(),
376 d->rect.y() + d->rect.height() / 2 - 1,
377 d->rect.x() + d->rect.width(),
378 d->rect.y() + d->rect.height() / 2 - 1);
379 p.setPen(QPen(Qt::red, 2, Qt::DotLine));
380 p.drawLine(d->rect.x(),
381 d->rect.y() + d->rect.height() / 2 - 1,
382 d->rect.x() + d->rect.width(),
383 d->rect.y() + d->rect.height() / 2 - 1);
384
385 drawText(&p, QPoint(d->rect.x() + 20, d->rect.y() + 20), beforeLabel.toString());
386 drawText(&p, QPoint(d->rect.x() + 20, d->rect.y() + d->rect.height() / 2 + 20), afterLabel.toString());
387 }
388
389 if (d->spotVisible)
390 {
391 // Adapt spot from image coordinate to widget coordinate.
392
393 int xspot = d->spot.x() + d->rect.x();
394 int yspot = d->spot.y() + d->rect.y();
395
396 switch (d->guideMode)
397 {
398 case HVGuideMode:
399 {
400 p.setPen(QPen(Qt::white, d->guideSize, Qt::SolidLine));
401 p.drawLine(xspot, d->rect.top() + d->flicker, xspot, d->rect.bottom() - d->flicker);
402 p.drawLine(d->rect.left() + d->flicker, yspot, d->rect.right() - d->flicker, yspot);
403 p.setPen(QPen(d->guideColor, d->guideSize, Qt::DotLine));
404 p.drawLine(xspot, d->rect.top() + d->flicker, xspot, d->rect.bottom() - d->flicker);
405 p.drawLine(d->rect.left() + d->flicker, yspot, d->rect.right() - d->flicker, yspot);
406 break;
407 }
408
409 case PickColorMode:
410 {
411 p.setPen(QPen(d->guideColor, 1, Qt::SolidLine));
412 p.drawLine(xspot - 10, yspot - 10, xspot + 10, yspot + 10);
413 p.drawLine(xspot + 10, yspot - 10, xspot - 10, yspot + 10);
414 p.setPen(QPen(d->guideColor, 3, Qt::SolidLine));
415 p.drawEllipse(xspot - 5, yspot - 5, 11, 11);
416
417 if (d->flicker % 2 != 0)
418 {
419 p.setPen(QPen(Qt::white, 1, Qt::SolidLine));
420 p.drawEllipse(xspot - 5, yspot - 5, 11, 11);
421 }
422
423 break;
424 }
425 }
426 }
427
428 // draw additional points added by the image tool
429
430 if (d->selectedPoints.count() > 0)
431 {
432 QPainter::RenderHints hints = p.renderHints();
433 QColor semiTransGuideColor = QColor(d->guideColor.red(), d->guideColor.green(), d->guideColor.blue(), 75);
434
435 QPoint point;
436 int x = 0;
437 int y = 0;
438
439 for (int i = 0 ; i < d->selectedPoints.count() ; ++i)
440 {
441 point = d->selectedPoints.point(i);
442 point = translatePointPosition(point);
443 x = point.x();
444 y = point.y();
445
446 p.save();
447 p.setRenderHint(QPainter::Antialiasing, true);
448 p.setPen(QPen(d->guideColor, 2, Qt::SolidLine));
449 p.setBrush(QBrush(semiTransGuideColor));
450 p.drawEllipse(point, 6, 6);
451
452 p.restore();
453 p.setPen(QPen(d->guideColor, 1, Qt::SolidLine));
454 p.setBrush(Qt::NoBrush);
455 p.setRenderHint(QPainter::Antialiasing, false);
456 p.drawPoint(point);
457 p.drawText(QPoint(x + 10, y - 5), QString::number(i + 1));
458
459 // draw a line between the points
460
461 if (d->drawLineBetweenPoints &&
462 ((i + 1) < d->selectedPoints.count()) && !d->selectedPoints.point(i + 1).isNull())
463 {
464 p.save();
465 p.setPen(QPen(d->guideColor, d->guideSize, Qt::SolidLine));
466 QPoint point2 = d->selectedPoints.point(i + 1);
467 point2 = translatePointPosition(point2);
468 p.setRenderHint(QPainter::Antialiasing, true);
469 p.drawLine(point, point2);
470 p.restore();
471 }
472 }
473
474 p.setRenderHints(hints);
475 }
476
477 p.end();
478 }
479
drawText(QPainter * const p,const QPoint & corner,const QString & text)480 void ImageGuideWidget::drawText(QPainter* const p, const QPoint& corner, const QString& text)
481 {
482 p->save();
483 QFontMetrics fontMt = p->fontMetrics();
484 QRect fontRect = fontMt.boundingRect(text);
485 QRect textRect;
486 textRect.setTopLeft(corner);
487 textRect.setSize(QSize(fontRect.width() + 5, fontRect.height() + 2));
488
489 // Draw background
490
491 p->setPen(Qt::black);
492 QColor semiTransBg = palette().color(QPalette::Window);
493 semiTransBg.setAlpha(190);
494 p->setBrush(semiTransBg);
495 /*
496 p->translate(0.5, 0.5);
497 */
498 p->drawRoundedRect(textRect, 10.0, 10.0);
499
500 // Draw shadow and text
501
502 p->setPen(palette().color(QPalette::Window).darker(115));
503 p->drawText(textRect.translated(3, 1), text);
504 p->setPen(palette().color(QPalette::WindowText));
505 p->drawText(textRect.translated(2, 0), text);
506
507 p->restore();
508 }
509
paintEvent(QPaintEvent *)510 void ImageGuideWidget::paintEvent(QPaintEvent*)
511 {
512 QPainter p(this);
513 p.drawPixmap(0, 0, *d->pixmap);
514
515 if (d->enableDrawMask && d->onMouseMovePreviewToggled == false)
516 {
517 p.setOpacity(0.7);
518 p.drawPixmap(d->rect.x(), d->rect.y(), *d->maskPixmap);
519
520 if ((d->renderingPreviewMode == PreviewToolBar::PreviewOriginalImage) ||
521 ((d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) && !d->onMouseMovePreviewToggled))
522 {
523 drawText(&p, QPoint(d->rect.x() + 20, d->rect.y() + 20), beforeLabel.toString());
524 }
525 else if ((d->renderingPreviewMode == PreviewToolBar::PreviewTargetImage) ||
526 (d->renderingPreviewMode == PreviewToolBar::NoPreviewMode) ||
527 ((d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) && d->onMouseMovePreviewToggled))
528 {
529 drawText(&p, QPoint(d->rect.x() + 20, d->rect.y() + 20), afterLabel.toString());
530 }
531 }
532
533 p.end();
534 }
535
timerEvent(QTimerEvent * e)536 void ImageGuideWidget::timerEvent(QTimerEvent* e)
537 {
538 if (e->timerId() == d->timerID)
539 {
540 if (d->flicker == 5)
541 {
542 d->flicker = 0;
543 }
544 else
545 {
546 d->flicker++;
547 }
548
549 updatePreview();
550 }
551 else
552 {
553 QWidget::timerEvent(e);
554 }
555 }
556
resizeEvent(QResizeEvent * e)557 void ImageGuideWidget::resizeEvent(QResizeEvent* e)
558 {
559 blockSignals(true);
560 delete d->pixmap;
561 delete d->previewPixmap;
562
563 int w = e->size().width();
564 int h = e->size().height();
565 int old_w = d->preview.width();
566 int old_h = d->preview.height();
567 d->preview = d->iface->setPreviewSize(QSize(w, h));
568 d->preview.setIccProfile(d->iface->original() ? d->iface->original()->getIccProfile() : IccProfile());
569
570 d->pixmap = new QPixmap(w, h);
571 d->previewPixmap = new QPixmap(w, h);
572 d->rect = QRect(w / 2 - d->preview.width() / 2, h / 2 - d->preview.height() / 2, d->preview.width(), d->preview.height());
573 *d->maskPixmap = d->maskPixmap->scaled(d->preview.width(), d->preview.height(), Qt::IgnoreAspectRatio);
574 *d->previewPixmap = d->iface->convertToPixmap(d->preview);
575
576 d->spot.setX((int)((float)d->spot.x() * ((float)d->preview.width() / (float)old_w)));
577 d->spot.setY((int)((float)d->spot.y() * ((float)d->preview.height() / (float)old_h)));
578 updatePixmap();
579
580 blockSignals(false);
581 emit signalResized();
582 }
583
mousePressEvent(QMouseEvent * e)584 void ImageGuideWidget::mousePressEvent(QMouseEvent* e)
585 {
586 if (e->button() == Qt::LeftButton)
587 {
588 if (!d->focus && d->rect.contains(e->x(), e->y()) && d->spotVisible)
589 {
590 d->focus = true;
591 d->spot.setX(e->x() - d->rect.x());
592 d->spot.setY(e->y() - d->rect.y());
593 }
594 else if (d->enableDrawMask)
595 {
596 d->lastPoint = QPoint(e->x() - d->rect.x(), e->y() - d->rect.y());
597 d->drawingMask = true;
598 }
599
600 updatePreview();
601 }
602 }
603
mouseReleaseEvent(QMouseEvent * e)604 void ImageGuideWidget::mouseReleaseEvent(QMouseEvent* e)
605 {
606 if (d->rect.contains(e->x(), e->y()))
607 {
608 if (d->focus && d->spotVisible)
609 {
610 d->focus = false;
611 updatePreview();
612 d->spot.setX(e->x() - d->rect.x());
613 d->spot.setY(e->y() - d->rect.y());
614
615 DColor color;
616 /*
617 QPoint point = getSpotPosition();
618 */
619 if (d->renderingPreviewMode == PreviewToolBar::PreviewOriginalImage)
620 {
621 color = getSpotColor(OriginalImage);
622 emit spotPositionChangedFromOriginal(color, d->spot);
623 }
624 else if ((d->renderingPreviewMode == PreviewToolBar::PreviewTargetImage) ||
625 (d->renderingPreviewMode == PreviewToolBar::NoPreviewMode))
626 {
627 color = getSpotColor(TargetPreviewImage);
628 emit spotPositionChangedFromTarget(color, d->spot);
629 }
630 else if (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVert)
631 {
632 if (d->spot.x() > (d->rect.width() / 2))
633 {
634 color = getSpotColor(TargetPreviewImage);
635 emit spotPositionChangedFromTarget(color, QPoint(d->spot.x() - d->rect.width() / 2,
636 d->spot.y()));
637 }
638 else
639 {
640 color = getSpotColor(OriginalImage);
641 emit spotPositionChangedFromOriginal(color, d->spot);
642 }
643 }
644 else if (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVertCont)
645 {
646 if (d->spot.x() > (d->rect.width() / 2))
647 {
648 color = getSpotColor(TargetPreviewImage);
649 emit spotPositionChangedFromTarget(color, d->spot);
650 }
651 else
652 {
653 color = getSpotColor(OriginalImage);
654 emit spotPositionChangedFromOriginal(color, d->spot);
655 }
656 }
657 else if (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorz)
658 {
659 if (d->spot.y() > (d->rect.height() / 2))
660 {
661 color = getSpotColor(TargetPreviewImage);
662 emit spotPositionChangedFromTarget(color, QPoint(d->spot.x(),
663 d->spot.y() - d->rect.height() / 2));
664 }
665 else
666 {
667 color = getSpotColor(OriginalImage);
668 emit spotPositionChangedFromOriginal(color, d->spot);
669 }
670 }
671 else if (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorzCont)
672 {
673 if (d->spot.y() > (d->rect.height() / 2))
674 {
675 color = getSpotColor(TargetPreviewImage);
676 emit spotPositionChangedFromTarget(color, d->spot);
677 }
678 else
679 {
680 color = getSpotColor(OriginalImage);
681 emit spotPositionChangedFromOriginal(color, d->spot);
682 }
683 }
684 }
685 else if (e->button() == Qt::LeftButton && d->drawingMask)
686 {
687 d->drawingMask = false;
688 updatePreview();
689 }
690 }
691 }
692
mouseMoveEvent(QMouseEvent * e)693 void ImageGuideWidget::mouseMoveEvent(QMouseEvent* e)
694 {
695 if (d->rect.contains(e->x(), e->y()))
696 {
697 if (d->focus && d->spotVisible)
698 {
699 setCursor(Qt::CrossCursor);
700 d->spot.setX(e->x() - d->rect.x());
701 d->spot.setY(e->y() - d->rect.y());
702 }
703 else if (d->enableDrawMask)
704 {
705 setCursor(d->maskCursor);
706
707 if ((e->buttons() & Qt::LeftButton) && d->drawingMask)
708 {
709 QPoint currentPos = QPoint(e->x() - d->rect.x(), e->y() - d->rect.y());
710 drawLineTo(currentPos);
711 updatePreview();
712 }
713 }
714 }
715 else
716 {
717 unsetCursor();
718 }
719 }
720
enterEvent(QEvent *)721 void ImageGuideWidget::enterEvent(QEvent*)
722 {
723 if (!d->focus && (d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver))
724 {
725 d->onMouseMovePreviewToggled = false;
726 updatePixmap();
727 repaint();
728 }
729 }
730
leaveEvent(QEvent *)731 void ImageGuideWidget::leaveEvent(QEvent*)
732 {
733 if (!d->focus && (d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver))
734 {
735 d->onMouseMovePreviewToggled = true;
736 updatePixmap();
737 update();
738 }
739 }
740
setPoints(const QPolygon & p,bool drawLine)741 void ImageGuideWidget::setPoints(const QPolygon& p, bool drawLine)
742 {
743 d->selectedPoints = p;
744 d->drawLineBetweenPoints = drawLine;
745 updatePreview();
746 }
747
resetPoints()748 void ImageGuideWidget::resetPoints()
749 {
750 d->selectedPoints.clear();
751 }
752
drawLineTo(const QPoint & endPoint)753 void ImageGuideWidget::drawLineTo(const QPoint& endPoint)
754 {
755 drawLineTo(d->penWidth, d->eraseMask, d->paintColor, d->lastPoint, endPoint);
756 }
757
drawLineTo(int width,bool erase,const QColor & color,const QPoint & start,const QPoint & end)758 void ImageGuideWidget::drawLineTo(int width, bool erase, const QColor& color, const QPoint& start, const QPoint& end)
759 {
760
761 QPainter painter(d->maskPixmap);
762
763 if (erase)
764 {
765 // drawLine() seems to ignore composition modes, use a tmp pixmap and combine it later on
766
767 QPixmap tmpMask(d->maskPixmap->width(), d->maskPixmap->height());
768 tmpMask.fill(Qt::transparent);
769 QPainter tmpPainter(&tmpMask);
770
771 painter.setRenderHint(QPainter::Antialiasing, false);
772 painter.setCompositionMode(QPainter::CompositionMode_DestinationOut);
773
774 QPen eraser;
775 eraser.setColor(Qt::yellow);
776 eraser.setStyle(Qt::SolidLine);
777 eraser.setWidth(width);
778 eraser.setCapStyle(Qt::RoundCap);
779 eraser.setJoinStyle(Qt::RoundJoin);
780
781 tmpPainter.setPen(eraser);
782 tmpPainter.setBrush(QBrush());
783 tmpPainter.drawLine(start, end);
784 tmpPainter.end();
785
786 painter.drawPixmap(0, 0, tmpMask);
787 }
788 else
789 {
790 painter.setPen(QPen(color, width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
791 painter.drawLine(start, end);
792 }
793
794 int rad = (width / 2) + 2;
795
796 update(QRect(start, end).normalized().adjusted(-rad, -rad, +rad, +rad));
797 d->lastPoint = end;
798
799 painter.end();
800 }
801
setPaintColor(const QColor & color)802 void ImageGuideWidget::setPaintColor(const QColor& color)
803 {
804 d->paintColor = color;
805 }
806
setMaskEnabled(bool enabled)807 void ImageGuideWidget::setMaskEnabled(bool enabled)
808 {
809 d->enableDrawMask = enabled;
810 unsetCursor();
811 updatePreview();
812 }
813
setEraseMode(bool erase)814 void ImageGuideWidget::setEraseMode(bool erase)
815 {
816 d->eraseMask = erase;
817 }
818
getMask() const819 QImage ImageGuideWidget::getMask() const
820 {
821 QImage mask = d->maskPixmap->toImage();
822 return mask;
823 }
824
translatePointPosition(const QPoint & point) const825 QPoint ImageGuideWidget::translatePointPosition(const QPoint& point) const
826 {
827 int x = d->rect.x() + 1 + (int)(point.x() * (float)d->preview.width() /
828 (float)d->iface->originalSize().width());
829 int y = d->rect.y() + 1 + (int)(point.y() * (float)d->preview.height() /
830 (float)d->iface->originalSize().height());
831
832 return (QPoint(x, y));
833 }
834
setMaskPenSize(int size)835 void ImageGuideWidget::setMaskPenSize(int size)
836 {
837 d->penWidth = size;
838 updateMaskCursor();
839 }
840
updateMaskCursor()841 void ImageGuideWidget::updateMaskCursor()
842 {
843 int size = d->penWidth;
844
845 if (size > 64)
846 {
847 size = 64;
848 }
849
850 if (size < 3)
851 {
852 size = 3;
853 }
854
855 QPixmap pix(size, size);
856 pix.fill(Qt::transparent);
857
858 QPainter p(&pix);
859 p.setRenderHint(QPainter::Antialiasing, true);
860
861 p.drawEllipse(1, 1, size - 2, size - 2);
862
863 d->maskCursor = QCursor(pix);
864 }
865
setSpotPosition(const QPoint & point)866 void ImageGuideWidget::setSpotPosition(const QPoint& point)
867 {
868 d->spot.setX(point.x());
869 d->spot.setY(point.y());
870 updatePreview();
871 }
872
updateSpotPosition(int x,int y)873 void ImageGuideWidget::updateSpotPosition(int x, int y)
874 {
875 QPoint origin = d->rect.topLeft();
876 x -= origin.x();
877 y -= origin.y();
878 d->spot.setX(x);
879 d->spot.setY(y);
880 updatePreview();
881 }
882
translateItemPosition(const QPoint & point,bool src) const883 QPoint ImageGuideWidget::translateItemPosition(const QPoint& point, bool src) const
884 {
885 int x = (int)(point.x() * (float)d->preview.width() /
886 (float) d->iface->originalSize().width());
887 int y = (int)(point.y() * (float)d->preview.height() /
888 (float) d->iface->originalSize().height());
889
890 if (!src)
891 {
892 x = (int)(point.x());
893 y = (int)(point.y());
894 x -= (int)(d->rect.topLeft().x()) + 1;
895 y -= (int)(d->rect.topLeft().y()) + 1;
896 }
897
898 return (QPoint(x, y));
899 }
900
setMaskCursor()901 void ImageGuideWidget::setMaskCursor()
902 {
903 if (d->enableDrawMask)
904 {
905 updateMaskCursor();
906 setCursor(d->maskCursor);
907 updatePreview();
908 }
909 }
910
911 } // namespace Digikam
912