diff --git a/core/utilities/imageeditor/widgets/canvas.cpp b/core/utilities/imageeditor/widgets/canvas.cpp index 97b60e9676..e60bba5bb8 100644 --- a/core/utilities/imageeditor/widgets/canvas.cpp +++ b/core/utilities/imageeditor/widgets/canvas.cpp @@ -1,707 +1,714 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2013-08-04 * Description : image editor canvas management class * * Copyright (C) 2013-2014 by Yiou Wang * Copyright (C) 2004-2005 by Renchi Raju * Copyright (C) 2004-2020 by Gilles Caulier * * 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, 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. * * ============================================================ */ #include "canvas.h" // Qt includes #include #include #include #include #include #include // KDE includes #include // Local includes #include "imagehistogram.h" #include "iccsettingscontainer.h" #include "icctransform.h" #include "exposurecontainer.h" #include "iofilesettings.h" #include "loadingcacheinterface.h" #include "imagepreviewitem.h" #include "previewlayout.h" #include "imagezoomsettings.h" #include "clickdragreleaseitem.h" #include "rubberitem.h" namespace Digikam { class Q_DECL_HIDDEN Canvas::Private { public: explicit Private() + : canvasItem(nullptr), + rubber(nullptr), + wrapItem(nullptr), + core(nullptr) { - rubber = nullptr; - wrapItem = nullptr; - canvasItem = nullptr; - core = nullptr; } QString errorMessage; ImagePreviewItem* canvasItem; RubberItem* rubber; ClickDragReleaseItem* wrapItem; EditorCore* core; }; Canvas::Canvas(QWidget* const parent) : GraphicsDImgView(parent), d(new Private) { d->core = new EditorCore(); d->canvasItem = new ImagePreviewItem; setItem(d->canvasItem); setFrameStyle(QFrame::NoFrame); addRubber(); layout()->fitToWindow(); installPanIcon(); setAcceptDrops(true); viewport()->setAcceptDrops(true); // ------------------------------------------------------------ connect(d->core, SIGNAL(signalModified()), this, SLOT(slotModified())); connect(d->core, SIGNAL(signalLoadingStarted(QString)), this, SIGNAL(signalLoadingStarted(QString))); connect(d->core, SIGNAL(signalImageLoaded(QString,bool)), this, SLOT(slotImageLoaded(QString,bool))); connect(d->core, SIGNAL(signalImageSaved(QString,bool)), this, SLOT(slotImageSaved(QString,bool))); connect(d->core, SIGNAL(signalLoadingProgress(QString,float)), this, SIGNAL(signalLoadingProgress(QString,float))); connect(d->core, SIGNAL(signalSavingStarted(QString)), this, SIGNAL(signalSavingStarted(QString))); connect(d->core, SIGNAL(signalSavingProgress(QString,float)), this, SIGNAL(signalSavingProgress(QString,float))); connect(this, SIGNAL(signalSelected(bool)), this, SLOT(slotSelected())); connect(d->canvasItem, SIGNAL(showContextMenu(QGraphicsSceneContextMenuEvent*)), this, SIGNAL(signalRightButtonClicked())); connect(layout(), SIGNAL(zoomFactorChanged(double)), this, SIGNAL(signalZoomChanged(double))); } Canvas::~Canvas() { delete d->core; delete d->canvasItem; delete d; } void Canvas::resetImage() { reset(); d->core->resetImage(); } void Canvas::reset() { if (d->rubber && d->rubber->isVisible()) { d->rubber->setVisible(false); if (d->core->isValid()) { emit signalSelected(false); } } addRubber(); d->errorMessage.clear(); } void Canvas::load(const QString& filename, IOFileSettings* const IOFileSettings) { reset(); emit signalPrepareToLoad(); d->core->load(filename, IOFileSettings); } void Canvas::slotImageLoaded(const QString& filePath, bool success) { if (d->core->getImg()) { d->canvasItem->setImage(*d->core->getImg()); } // Note: in showFoto, we using a null filename to clear canvas. + if (!success && !filePath.isEmpty()) { QFileInfo info(filePath); d->errorMessage = i18n("Failed to load image\n\"%1\"", info.fileName()); } else { d->errorMessage.clear(); } viewport()->update(); emit signalLoadingFinished(filePath, success); } void Canvas::fitToSelect() { QRect sel = d->core->getSelectedArea(); if (!sel.size().isNull()) { // If selected area, use center of selection // and recompute zoom factor accordingly. + double cpx = sel.x() + sel.width() / 2.0; double cpy = sel.y() + sel.height() / 2.0; double srcWidth = sel.width(); double srcHeight = sel.height(); double dstWidth = contentsRect().width(); double dstHeight = contentsRect().height(); double zoom = qMin(dstWidth / srcWidth, dstHeight / srcHeight); emit signalToggleOffFitToWindow(); layout()->setZoomFactor(zoom); centerOn(cpx * zoom, cpy * zoom); viewport()->update(); } } void Canvas::applyTransform(const IccTransform& t) { IccTransform transform(t); if (transform.willHaveEffect()) { d->core->applyTransform(transform); } else { viewport()->update(); } } void Canvas::preload(const QString& /*filename*/) { - // d->core->preload(filename); +/* + d->core->preload(filename); +*/ } void Canvas::slotImageSaved(const QString& filePath, bool success) { emit signalSavingFinished(filePath, success); } void Canvas::abortSaving() { d->core->abortSaving(); } void Canvas::setModified() { d->core->setModified(); } QString Canvas::ensureHasCurrentUuid() const { return d->core->ensureHasCurrentUuid(); } DImg Canvas::currentImage() const { DImg* const image = d->core->getImg(); if (image) { return DImg(*image); } return DImg(); } QString Canvas::currentImageFileFormat() const { return d->core->getImageFormat(); } QString Canvas::currentImageFilePath() const { return d->core->getImageFilePath(); } int Canvas::imageWidth() const { return d->core->origWidth(); } int Canvas::imageHeight() const { return d->core->origHeight(); } bool Canvas::isReadOnly() const { return d->core->isReadOnly(); } QRect Canvas::getSelectedArea() const { return d->core->getSelectedArea(); } EditorCore* Canvas::interface() const { return d->core; } void Canvas::makeDefaultEditingCanvas() { EditorCore::setDefaultInstance(d->core); } bool Canvas::exifRotated() const { return d->core->exifRotated(); } void Canvas::slotRotate90() { d->canvasItem->clearCache(); d->core->rotate90(); } void Canvas::slotRotate180() { d->canvasItem->clearCache(); d->core->rotate180(); } void Canvas::slotRotate270() { d->canvasItem->clearCache(); d->core->rotate270(); } void Canvas::slotFlipHoriz() { d->canvasItem->clearCache(); d->core->flipHoriz(); } void Canvas::slotFlipVert() { d->canvasItem->clearCache(); d->core->flipVert(); } void Canvas::slotCrop() { d->canvasItem->clearCache(); QRect sel = d->core->getSelectedArea(); if (sel.size().isNull()) // No current selection. { return; } d->core->crop(sel); if (d->rubber && d->rubber->isVisible()) { d->rubber->setVisible(false); } emit signalSelected(false); addRubber(); } void Canvas::setICCSettings(const ICCSettingsContainer& cmSettings) { d->canvasItem->clearCache(); d->core->setICCSettings(cmSettings); viewport()->update(); } void Canvas::setSoftProofingEnabled(bool enable) { d->canvasItem->clearCache(); d->core->setSoftProofingEnabled(enable); viewport()->update(); } void Canvas::setExposureSettings(ExposureSettingsContainer* const expoSettings) { d->canvasItem->clearCache(); d->core->setExposureSettings(expoSettings); viewport()->update(); } void Canvas::setExifOrient(bool exifOrient) { d->canvasItem->clearCache(); d->core->setExifOrient(exifOrient); viewport()->update(); } void Canvas::slotRestore() { d->core->restore(); viewport()->update(); } void Canvas::slotUndo(int steps) { emit signalUndoSteps(steps); d->canvasItem->clearCache(); while (steps > 0) { d->core->undo(); --steps; } } void Canvas::slotRedo(int steps) { emit signalRedoSteps(steps); d->canvasItem->clearCache(); while (steps > 0) { d->core->redo(); --steps; } } void Canvas::slotCopy() { QRect sel = d->core->getSelectedArea(); if (sel.size().isNull()) // No current selection. { return; } QApplication::setOverrideCursor(Qt::WaitCursor); DImg selDImg = d->core->getImgSelection(); QImage selImg = selDImg.copyQImage(); QMimeData* const mimeData = new QMimeData(); mimeData->setImageData(selImg); QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); QApplication::restoreOverrideCursor(); } void Canvas::slotSelected() { QRect sel = QRect(0, 0, 0, 0); if (d->wrapItem) { cancelAddItem(); return; } if (d->rubber) { sel = calcSelectedArea(); } d->core->setSelectedArea(sel); emit signalSelectionChanged(sel); } void Canvas::slotSelectionMoved() { QRect sel = QRect(0, 0, 0, 0); if (d->rubber) { sel = calcSelectedArea(); } emit signalSelectionSetText(sel); } QRect Canvas::calcSelectedArea() const { int x = 0, y = 0, w = 0, h = 0; double z = layout()->realZoomFactor(); if (d->rubber && d->rubber->isVisible()) { QRect r(d->rubber->boundingRect().toRect()); if (r.isValid()) { r.translate((int)d->rubber->x(), (int)d->rubber->y()); x = (int)((double)r.x() / z); y = (int)((double)r.y() / z); w = (int)((double)r.width() / z); h = (int)((double)r.height() / z); x = qMin(imageWidth(), qMax(x, 0)); y = qMin(imageHeight(), qMax(y, 0)); w = qMin(imageWidth(), qMax(w, 0)); h = qMin(imageHeight(), qMax(h, 0)); // Avoid empty selection by rubberband - at least mark one pixel // At high zoom factors, the rubberband may operate at subpixel level! + if (w == 0) { w = 1; } if (h == 0) { h = 1; } } } return QRect(x, y, w, h); } void Canvas::slotModified() { d->canvasItem->setImage(currentImage()); emit signalChanged(); } void Canvas::slotSelectAll() { if (d->rubber) { delete d->rubber; } d->rubber = new RubberItem(d->canvasItem); d->rubber->setCanvas(this); d->rubber->setRectInSceneCoordinatesAdjusted(d->canvasItem->boundingRect()); viewport()->setMouseTracking(true); viewport()->update(); if (d->core->isValid()) { emit signalSelected(true); } } void Canvas::slotSelectNone() { reset(); viewport()->update(); } void Canvas::keyPressEvent(QKeyEvent* event) { if (!event) { return; } int mult = 1; if ((event->modifiers() & Qt::ControlModifier)) { mult = 10; } switch (event->key()) { case Qt::Key_Right: { horizontalScrollBar()->setValue(horizontalScrollBar()->value() + horizontalScrollBar()->singleStep()*mult); break; } case Qt::Key_Left: { horizontalScrollBar()->setValue(horizontalScrollBar()->value() - horizontalScrollBar()->singleStep()*mult); break; } case Qt::Key_Up: { verticalScrollBar()->setValue(verticalScrollBar()->value() - verticalScrollBar()->singleStep()*mult); break; } case Qt::Key_Down: { verticalScrollBar()->setValue(verticalScrollBar()->value() + verticalScrollBar()->singleStep()*mult); break; } default: { event->ignore(); break; } } } void Canvas::addRubber() { if (!d->wrapItem) { d->wrapItem = new ClickDragReleaseItem(d->canvasItem); } d->wrapItem->setFocus(); setFocus(); connect(d->wrapItem, SIGNAL(started(QPointF)), this, SLOT(slotAddItemStarted(QPointF))); connect(d->wrapItem, SIGNAL(moving(QRectF)), this, SLOT(slotAddItemMoving(QRectF))); connect(d->wrapItem, SIGNAL(finished(QRectF)), this, SLOT(slotAddItemFinished(QRectF))); connect(d->wrapItem, SIGNAL(cancelled()), this, SLOT(cancelAddItem())); } void Canvas::slotAddItemStarted(const QPointF& pos) { Q_UNUSED(pos); } void Canvas::slotAddItemMoving(const QRectF& rect) { if (d->rubber) { delete d->rubber; } d->rubber = new RubberItem(d->canvasItem); d->rubber->setCanvas(this); d->rubber->setRectInSceneCoordinatesAdjusted(rect); } void Canvas::slotAddItemFinished(const QRectF& rect) { if (d->rubber) { d->rubber->setRectInSceneCoordinatesAdjusted(rect); - //d->wrapItem->stackBefore(d->canvasItem); +/* + d->wrapItem->stackBefore(d->canvasItem); +*/ } cancelAddItem(); } void Canvas::cancelAddItem() { if (d->wrapItem) { this->scene()->removeItem(d->wrapItem); d->wrapItem->deleteLater(); d->wrapItem = nullptr; } emit signalSelected(true); } void Canvas::mousePressEvent(QMouseEvent* event) { GraphicsDImgView::mousePressEvent(event); if (event->button() == Qt::LeftButton) { GraphicsDImgItem* const item = dynamic_cast(itemAt(event->pos())); if (item) { QLatin1String className(item->metaObject()->className()); if (!(className == QLatin1String("Digikam::RubberItem") || className == QLatin1String("Digikam::ClickDragReleaseItem"))) { if (d->rubber && d->rubber->isVisible()) { d->rubber->setVisible(false); } emit signalSelected(false); addRubber(); } } } } void Canvas::dragEnterEvent(QDragEnterEvent* e) { QGraphicsView::dragEnterEvent(e); if (e->mimeData()->hasUrls()) { e->acceptProposedAction(); } } void Canvas::dragMoveEvent(QDragMoveEvent* e) { QGraphicsView::dragMoveEvent(e); if (e->mimeData()->hasUrls()) { e->acceptProposedAction(); } } void Canvas::dropEvent(QDropEvent* e) { QGraphicsView::dropEvent(e); emit signalAddedDropedItems(e); } } // namespace Digikam diff --git a/core/utilities/imageeditor/widgets/canvas.h b/core/utilities/imageeditor/widgets/canvas.h index a4284f9570..8e0269b2cc 100644 --- a/core/utilities/imageeditor/widgets/canvas.h +++ b/core/utilities/imageeditor/widgets/canvas.h @@ -1,211 +1,226 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2013-08-04 * Description : image editor canvas management class * * Copyright (C) 2013-2014 by Yiou Wang * Copyright (C) 2004-2005 by Renchi Raju * Copyright (C) 2004-2020 by Gilles Caulier * * 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, 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. * * ============================================================ */ #ifndef DIGIKAM_IMAGE_EDITOR_CANVAS_H #define DIGIKAM_IMAGE_EDITOR_CANVAS_H // Qt includes #include #include #include #include // Local includes #include "digikam_export.h" #include "dimg.h" #include "graphicsdimgview.h" #include "editorcore.h" class QWheelEvent; class QKeyEvent; namespace Digikam { class EditorCore; class ExposureSettingsContainer; class ICCSettingsContainer; class IccTransform; class IOFileSettings; class DIGIKAM_EXPORT Canvas : public GraphicsDImgView { Q_OBJECT public: explicit Canvas(QWidget* const parent = nullptr); ~Canvas(); void load(const QString& filename, IOFileSettings* const IOFileSettings); void preload(const QString& filename); void resetImage(); void abortSaving(); void setModified(); void makeDefaultEditingCanvas(); QString ensureHasCurrentUuid() const; - /** Return the core interface instance of editor. + /** + * Return the core interface instance of editor. */ EditorCore* interface() const; - /** Return a copy of current image loaded in editor. + /** + * Return a copy of current image loaded in editor. */ DImg currentImage() const; - /** Return the type mime of current image loaded in editor. + /** + * Return the type mime of current image loaded in editor. */ QString currentImageFileFormat() const; - /** Return the file path of current image loaded in editor. + /** + * Return the file path of current image loaded in editor. */ QString currentImageFilePath() const; - /** Return the width of current image loaded in editor. + /** + * Return the width of current image loaded in editor. */ int imageWidth() const; - /** Return the height of current image loaded in editor. + /** + * Return the height of current image loaded in editor. */ int imageHeight() const; - /** Return the rectangle information of current canvas selection. + /** + * Return the rectangle information of current canvas selection. */ QRect getSelectedArea() const; - /** If current image file format is only available in read only, - * typically all RAW image file formats. + /** + * If current image file format is only available in read only, + * typically all RAW image file formats. */ bool isReadOnly() const; - /** Apply Color management settings (typically screen profile). + /** + * Apply Color management settings (typically screen profile). */ void setICCSettings(const ICCSettingsContainer& cmSettings); - /** Apply Color Management transformation to image (typically working color space). + /** + * Apply Color Management transformation to image (typically working color space). */ void applyTransform(const IccTransform& transform); - /** Apply under.over exposure indicator settings. + /** + * Apply under.over exposure indicator settings. */ void setExposureSettings(ExposureSettingsContainer* const expoSettings); - /** Turn on/off Color Management Soft proofing mode. + /** + * Turn on/off Color Management Soft proofing mode. */ void setSoftProofingEnabled(bool enable); - /** Rotate image following Exif information. + /** + * Rotate image following Exif information. */ void setExifOrient(bool exifOrient); - /** Return true if image have been rotated following Exif information. + /** + * Return true if image have been rotated following Exif information. */ bool exifRotated() const; - /** Change zoom level to fit current selection on canvas size. + /** + * Change zoom level to fit current selection on canvas size. */ void fitToSelect(); Q_SIGNALS: void signalChanged(); void signalSelected(bool); void signalRightButtonClicked(); void signalShowNextImage(); void signalShowPrevImage(); void signalPrepareToLoad(); void signalLoadingStarted(const QString& filename); void signalLoadingFinished(const QString& filename, bool success); void signalLoadingProgress(const QString& filePath, float progress); void signalSavingStarted(const QString& filename); void signalSavingFinished(const QString& filename, bool success); void signalSavingProgress(const QString& filePath, float progress); void signalSelectionChanged(const QRect&); void signalSelectionSetText(const QRect&); void signalToggleOffFitToWindow(); void signalUndoSteps(int); void signalRedoSteps(int); void signalZoomChanged(double); void signalAddedDropedItems(QDropEvent*); public Q_SLOTS: - // image modifiers + /// image modifiers void slotRotate90(); void slotRotate180(); void slotRotate270(); void slotFlipHoriz(); void slotFlipVert(); void slotCrop(); void slotRestore(); void slotUndo(int steps = 1); void slotRedo(int steps = 1); void slotCopy(); void slotSelectAll(); void slotSelectNone(); void slotSelected(); void slotSelectionMoved(); protected: void keyPressEvent(QKeyEvent*) override; void mousePressEvent(QMouseEvent*) override; void addRubber(); void dragMoveEvent(QDragMoveEvent*) override; void dragEnterEvent(QDragEnterEvent*) override; void dropEvent(QDropEvent*) override; private: QRect calcSelectedArea() const; void reset(); private Q_SLOTS: void slotModified(); void slotImageLoaded(const QString& filePath, bool success); void slotImageSaved(const QString& filePath, bool success); void slotAddItemStarted(const QPointF& pos); void slotAddItemMoving(const QRectF& rect); void slotAddItemFinished(const QRectF& rect); void cancelAddItem(); private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_IMAGE_EDITOR_CANVAS_H diff --git a/core/utilities/imageeditor/widgets/imageguidewidget.cpp b/core/utilities/imageeditor/widgets/imageguidewidget.cpp index 939de0b40c..7ab8e99a37 100644 --- a/core/utilities/imageeditor/widgets/imageguidewidget.cpp +++ b/core/utilities/imageeditor/widgets/imageguidewidget.cpp @@ -1,892 +1,911 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2004-11-16 * Description : a widget to display an image with guides * * Copyright (C) 2004-2020 by Gilles Caulier * * 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, 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. * * ============================================================ */ #include "imageguidewidget.h" // Qt includes #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "dimg.h" #include "digikam_debug.h" #include "previewtoolbar.h" #include "exposurecontainer.h" #include "iccsettingscontainer.h" namespace Digikam { static const KLocalizedString beforeLabel = ki18nc("Preview image (before filter has been applied)", "Before"); static const KLocalizedString afterLabel = ki18nc("Preview image (after filter has been applied)", "After"); class Q_DECL_HIDDEN ImageGuideWidget::Private { public: explicit Private() : sixteenBit(false), focus(false), spotVisible(false), onMouseMovePreviewToggled(true), drawLineBetweenPoints(false), drawingMask(false), enableDrawMask(false), eraseMask(false), timerID(0), guideMode(0), guideSize(0), flicker(0), renderingPreviewMode(PreviewToolBar::NoPreviewMode), penWidth(10), pixmap(nullptr), maskPixmap(nullptr), previewPixmap(nullptr), iface(nullptr) { } bool sixteenBit; bool focus; bool spotVisible; bool onMouseMovePreviewToggled; bool drawLineBetweenPoints; bool drawingMask; bool enableDrawMask; bool eraseMask; int timerID; int guideMode; int guideSize; int flicker; int renderingPreviewMode; int penWidth; - // Current spot position in preview coordinates. + /// Current spot position in preview coordinates. QPoint spot; QPolygon selectedPoints; QRect rect; QColor guideColor; QColor paintColor; QColor bgColor; QPixmap* pixmap; QPixmap* maskPixmap; QPixmap* previewPixmap; QCursor maskCursor; QPoint lastPoint; ImageIface* iface; DImg preview; }; ImageGuideWidget::ImageGuideWidget(QWidget* const parent, bool spotVisible, int guideMode, const QColor& guideColor, int guideSize, bool blink, ImageIface::PreviewType type) : QWidget(parent), d(new Private) { int w = 480; int h = 320; d->spotVisible = spotVisible; d->guideMode = guideMode; d->guideColor = guideColor; d->guideSize = guideSize; d->bgColor = palette().color(QPalette::Base); setMinimumSize(w, h); setMouseTracking(true); setAttribute(Qt::WA_DeleteOnClose); d->iface = new ImageIface(QSize(w, h)); d->iface->setPreviewType(type); d->preview = d->iface->preview(); d->preview.setIccProfile(d->iface->original() ? d->iface->original()->getIccProfile() : IccProfile()); d->pixmap = new QPixmap(w, h); d->rect = QRect(w / 2 - d->preview.width() / 2, h / 2 - d->preview.height() / 2, d->preview.width(), d->preview.height()); d->maskPixmap = new QPixmap(d->rect.width(), d->rect.height()); d->previewPixmap = new QPixmap(d->rect.width(), d->rect.height()); d->maskPixmap->fill(QColor(0, 0, 0, 0)); d->previewPixmap->fill(QColor(0, 0, 0, 0)); d->paintColor.setRgb(255, 255, 255, 255); d->lastPoint = QPoint(d->rect.x(), d->rect.y()); resetSpotPosition(); setSpotVisible(d->spotVisible, blink); } ImageGuideWidget::~ImageGuideWidget() { delete d->iface; if (d->timerID) { killTimer(d->timerID); } delete d->pixmap; delete d->maskPixmap; delete d->previewPixmap; delete d; } ImageIface* ImageGuideWidget::imageIface() const { return d->iface; } void ImageGuideWidget::setBackgroundColor(const QColor& bg) { d->bgColor = bg; updatePreview(); } void ImageGuideWidget::ICCSettingsChanged() { updatePreview(); } void ImageGuideWidget::exposureSettingsChanged() { updatePreview(); } void ImageGuideWidget::resetSpotPosition() { d->spot.setX(d->preview.width() / 2); d->spot.setY(d->preview.height() / 2); updatePreview(); } void ImageGuideWidget::slotPreviewModeChanged(int mode) { d->renderingPreviewMode = mode; updatePreview(); } int ImageGuideWidget::previewMode() const { return (d->renderingPreviewMode); } QPoint ImageGuideWidget::getSpotPosition() const { return (QPoint((int)((float)d->spot.x() * (float)d->iface->originalSize().width() / (float)d->preview.width()), (int)((float)d->spot.y() * (float)d->iface->originalSize().height() / (float)d->preview.height()))); } DColor ImageGuideWidget::getSpotColor(int getColorFrom) const { - if (getColorFrom == OriginalImage) // Get point color from full original image + if (getColorFrom == OriginalImage) // Get point color from full original image { return (d->iface->colorInfoFromOriginal(getSpotPosition())); } else if (getColorFrom == PreviewImage) // Get point color from full preview image { return (d->iface->colorInfoFromPreview(d->spot)); } // In other cases, get point color from preview target image + return (d->iface->colorInfoFromTargetPreview(d->spot)); } void ImageGuideWidget::setSpotVisible(bool spotVisible, bool blink) { d->spotVisible = spotVisible; if (blink) { if (d->spotVisible) { d->timerID = startTimer(800); } else { killTimer(d->timerID); d->timerID = 0; } } updatePreview(); } void ImageGuideWidget::setSpotVisibleNoUpdate(bool spotVisible) { d->spotVisible = spotVisible; } void ImageGuideWidget::slotChangeGuideColor(const QColor& color) { d->guideColor = color; updatePreview(); } void ImageGuideWidget::slotChangeGuideSize(int size) { d->guideSize = size; updatePreview(); } void ImageGuideWidget::updatePreview() { updatePixmap(); update(); } void ImageGuideWidget::updatePixmap() { QPainter p(d->pixmap); p.setRenderHint(QPainter::Antialiasing, true); p.setBackgroundMode(Qt::TransparentMode); QString text; p.setPen(QPen(Qt::red, 1)); d->pixmap->fill(d->bgColor); - if (d->renderingPreviewMode == PreviewToolBar::PreviewOriginalImage || - (d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver && !d->onMouseMovePreviewToggled)) + if ((d->renderingPreviewMode == PreviewToolBar::PreviewOriginalImage) || + ((d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) && !d->onMouseMovePreviewToggled)) { p.drawPixmap(d->rect, *d->previewPixmap); drawText(&p, QPoint(d->rect.x() + 20, d->rect.y() + 20), beforeLabel.toString()); } - else if (d->renderingPreviewMode == PreviewToolBar::PreviewTargetImage || - d->renderingPreviewMode == PreviewToolBar::NoPreviewMode || - (d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver && d->onMouseMovePreviewToggled)) + else if ((d->renderingPreviewMode == PreviewToolBar::PreviewTargetImage) || + (d->renderingPreviewMode == PreviewToolBar::NoPreviewMode) || + ((d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) && d->onMouseMovePreviewToggled)) { d->iface->paint(d->pixmap, d->rect, &p); - if (d->renderingPreviewMode == PreviewToolBar::PreviewTargetImage || - d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) + if ((d->renderingPreviewMode == PreviewToolBar::PreviewTargetImage) || + (d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver)) { drawText(&p, QPoint(d->rect.x() + 20, d->rect.y() + 20), afterLabel.toString()); } } - else if (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVert || - d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVertCont) + else if ((d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVert) || + (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVertCont)) { if (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVert) { // Drawing original image. + p.drawPixmap(d->rect, *d->previewPixmap); // Drawing target image under the original. + d->iface->paint(d->pixmap, QRect(d->rect.x() + d->rect.width() / 2, d->rect.y(), d->rect.width() / 2, d->rect.height()), &p); } else { // Drawing target image. + d->iface->paint(d->pixmap, d->rect, &p); // Drawing original image under the target. + p.drawPixmap(d->rect.x(), d->rect.y(), *d->previewPixmap, 0, 0, d->rect.width() / 2, d->rect.height()); } // Drawing information and others stuff. + p.fillRect(d->rect.right(), 0, width(), height(), palette().color(QPalette::Window)); p.setPen(QPen(Qt::white, 2, Qt::SolidLine)); p.drawLine(d->rect.x() + d->rect.width() / 2 - 1, d->rect.y(), d->rect.x() + d->rect.width() / 2 - 1, d->rect.y() + d->rect.height()); p.setPen(QPen(Qt::red, 2, Qt::DotLine)); p.drawLine(d->rect.x() + d->rect.width() / 2 - 1, d->rect.y(), d->rect.x() + d->rect.width() / 2 - 1, d->rect.y() + d->rect.height()); drawText(&p, QPoint(d->rect.x() + 20, d->rect.y() + 20), beforeLabel.toString()); drawText(&p, QPoint(d->rect.x() + d->rect.width() / 2 + 20, d->rect.y() + 20), afterLabel.toString()); } - else if (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorz || - d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorzCont) + else if ((d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorz) || + (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorzCont)) { if (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorz) { // Drawing original image. + p.drawPixmap(d->rect, *d->previewPixmap); // Drawing target image under the original. + d->iface->paint(d->pixmap, QRect(d->rect.x(), d->rect.y() + d->rect.height() / 2, d->rect.width(), d->rect.height() / 2), &p); } else { // Drawing target image. + d->iface->paint(d->pixmap, d->rect, &p); // Drawing original image under the target. + p.drawPixmap(d->rect.x(), d->rect.y(), *d->previewPixmap, 0, 0, d->rect.width(), d->rect.height() / 2); } p.fillRect(0, d->rect.bottom(), width(), height(), palette().color(QPalette::Window)); p.setPen(QPen(Qt::white, 2, Qt::SolidLine)); p.drawLine(d->rect.x(), d->rect.y() + d->rect.height() / 2 - 1, d->rect.x() + d->rect.width(), d->rect.y() + d->rect.height() / 2 - 1); p.setPen(QPen(Qt::red, 2, Qt::DotLine)); p.drawLine(d->rect.x(), d->rect.y() + d->rect.height() / 2 - 1, d->rect.x() + d->rect.width(), d->rect.y() + d->rect.height() / 2 - 1); drawText(&p, QPoint(d->rect.x() + 20, d->rect.y() + 20), beforeLabel.toString()); drawText(&p, QPoint(d->rect.x() + 20, d->rect.y() + d->rect.height() / 2 + 20), afterLabel.toString()); } if (d->spotVisible) { // Adapt spot from image coordinate to widget coordinate. + int xspot = d->spot.x() + d->rect.x(); int yspot = d->spot.y() + d->rect.y(); switch (d->guideMode) { case HVGuideMode: { p.setPen(QPen(Qt::white, d->guideSize, Qt::SolidLine)); p.drawLine(xspot, d->rect.top() + d->flicker, xspot, d->rect.bottom() - d->flicker); p.drawLine(d->rect.left() + d->flicker, yspot, d->rect.right() - d->flicker, yspot); p.setPen(QPen(d->guideColor, d->guideSize, Qt::DotLine)); p.drawLine(xspot, d->rect.top() + d->flicker, xspot, d->rect.bottom() - d->flicker); p.drawLine(d->rect.left() + d->flicker, yspot, d->rect.right() - d->flicker, yspot); break; } case PickColorMode: { p.setPen(QPen(d->guideColor, 1, Qt::SolidLine)); p.drawLine(xspot - 10, yspot - 10, xspot + 10, yspot + 10); p.drawLine(xspot + 10, yspot - 10, xspot - 10, yspot + 10); p.setPen(QPen(d->guideColor, 3, Qt::SolidLine)); p.drawEllipse(xspot - 5, yspot - 5, 11, 11); if (d->flicker % 2 != 0) { p.setPen(QPen(Qt::white, 1, Qt::SolidLine)); p.drawEllipse(xspot - 5, yspot - 5, 11, 11); } break; } } } // draw additional points added by the image tool + if (d->selectedPoints.count() > 0) { QPainter::RenderHints hints = p.renderHints(); QColor semiTransGuideColor = QColor(d->guideColor.red(), d->guideColor.green(), d->guideColor.blue(), 75); QPoint point; int x = 0; int y = 0; for (int i = 0 ; i < d->selectedPoints.count() ; ++i) { point = d->selectedPoints.point(i); point = translatePointPosition(point); x = point.x(); y = point.y(); p.save(); p.setRenderHint(QPainter::Antialiasing, true); p.setPen(QPen(d->guideColor, 2, Qt::SolidLine)); p.setBrush(QBrush(semiTransGuideColor)); p.drawEllipse(point, 6, 6); p.restore(); p.setPen(QPen(d->guideColor, 1, Qt::SolidLine)); p.setBrush(Qt::NoBrush); p.setRenderHint(QPainter::Antialiasing, false); p.drawPoint(point); p.drawText(QPoint(x + 10, y - 5), QString::number(i + 1)); // draw a line between the points + if (d->drawLineBetweenPoints && - (i + 1) < d->selectedPoints.count() && !d->selectedPoints.point(i + 1).isNull()) + ((i + 1) < d->selectedPoints.count()) && !d->selectedPoints.point(i + 1).isNull()) { p.save(); p.setPen(QPen(d->guideColor, d->guideSize, Qt::SolidLine)); QPoint point2 = d->selectedPoints.point(i + 1); point2 = translatePointPosition(point2); p.setRenderHint(QPainter::Antialiasing, true); p.drawLine(point, point2); p.restore(); } } p.setRenderHints(hints); } p.end(); } void ImageGuideWidget::drawText(QPainter* const p, const QPoint& corner, const QString& text) { p->save(); QFontMetrics fontMt = p->fontMetrics(); QRect fontRect = fontMt.boundingRect(text); QRect textRect; textRect.setTopLeft(corner); textRect.setSize(QSize(fontRect.width() + 5, fontRect.height() + 2)); // Draw background + p->setPen(Qt::black); QColor semiTransBg = palette().color(QPalette::Window); semiTransBg.setAlpha(190); p->setBrush(semiTransBg); - //p->translate(0.5, 0.5); +/* + p->translate(0.5, 0.5); +*/ p->drawRoundedRect(textRect, 10.0, 10.0); // Draw shadow and text + p->setPen(palette().color(QPalette::Window).darker(115)); p->drawText(textRect.translated(3, 1), text); p->setPen(palette().color(QPalette::WindowText)); p->drawText(textRect.translated(2, 0), text); p->restore(); } void ImageGuideWidget::paintEvent(QPaintEvent*) { QPainter p(this); p.drawPixmap(0, 0, *d->pixmap); if (d->enableDrawMask && d->onMouseMovePreviewToggled == false) { p.setOpacity(0.7); p.drawPixmap(d->rect.x(), d->rect.y(), *d->maskPixmap); - if (d->renderingPreviewMode == PreviewToolBar::PreviewOriginalImage || - (d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver && !d->onMouseMovePreviewToggled)) + if ((d->renderingPreviewMode == PreviewToolBar::PreviewOriginalImage) || + ((d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) && !d->onMouseMovePreviewToggled)) { drawText(&p, QPoint(d->rect.x() + 20, d->rect.y() + 20), beforeLabel.toString()); } - else if (d->renderingPreviewMode == PreviewToolBar::PreviewTargetImage || - d->renderingPreviewMode == PreviewToolBar::NoPreviewMode || - (d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver && d->onMouseMovePreviewToggled)) + else if ((d->renderingPreviewMode == PreviewToolBar::PreviewTargetImage) || + (d->renderingPreviewMode == PreviewToolBar::NoPreviewMode) || + ((d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) && d->onMouseMovePreviewToggled)) { drawText(&p, QPoint(d->rect.x() + 20, d->rect.y() + 20), afterLabel.toString()); } } p.end(); } void ImageGuideWidget::timerEvent(QTimerEvent* e) { if (e->timerId() == d->timerID) { if (d->flicker == 5) { d->flicker = 0; } else { d->flicker++; } updatePreview(); } else { QWidget::timerEvent(e); } } void ImageGuideWidget::resizeEvent(QResizeEvent* e) { blockSignals(true); delete d->pixmap; delete d->previewPixmap; int w = e->size().width(); int h = e->size().height(); int old_w = d->preview.width(); int old_h = d->preview.height(); d->preview = d->iface->setPreviewSize(QSize(w, h)); d->preview.setIccProfile(d->iface->original() ? d->iface->original()->getIccProfile() : IccProfile()); d->pixmap = new QPixmap(w, h); d->previewPixmap = new QPixmap(w, h); d->rect = QRect(w / 2 - d->preview.width() / 2, h / 2 - d->preview.height() / 2, d->preview.width(), d->preview.height()); *d->maskPixmap = d->maskPixmap->scaled(d->preview.width(), d->preview.height(), Qt::IgnoreAspectRatio); *d->previewPixmap = d->iface->convertToPixmap(d->preview); d->spot.setX((int)((float)d->spot.x() * ((float)d->preview.width() / (float)old_w))); d->spot.setY((int)((float)d->spot.y() * ((float)d->preview.height() / (float)old_h))); updatePixmap(); blockSignals(false); emit signalResized(); } void ImageGuideWidget::mousePressEvent(QMouseEvent* e) { if (e->button() == Qt::LeftButton) { - if (!d->focus && d->rect.contains(e->x(), e->y()) && d->spotVisible) + if (!d->focus && d->rect.contains(e->x(), e->y()) && d->spotVisible) { d->focus = true; d->spot.setX(e->x() - d->rect.x()); d->spot.setY(e->y() - d->rect.y()); } else if (d->enableDrawMask) { d->lastPoint = QPoint(e->x() - d->rect.x(), e->y() - d->rect.y()); d->drawingMask = true; } updatePreview(); } } void ImageGuideWidget::mouseReleaseEvent(QMouseEvent* e) { if (d->rect.contains(e->x(), e->y())) { if (d->focus && d->spotVisible) { d->focus = false; updatePreview(); d->spot.setX(e->x() - d->rect.x()); d->spot.setY(e->y() - d->rect.y()); DColor color; - // QPoint point = getSpotPosition(); - - if (d->renderingPreviewMode == PreviewToolBar::PreviewOriginalImage) +/* + QPoint point = getSpotPosition(); +*/ + if (d->renderingPreviewMode == PreviewToolBar::PreviewOriginalImage) { color = getSpotColor(OriginalImage); emit spotPositionChangedFromOriginal(color, d->spot); } - else if (d->renderingPreviewMode == PreviewToolBar::PreviewTargetImage || - d->renderingPreviewMode == PreviewToolBar::NoPreviewMode) + else if ((d->renderingPreviewMode == PreviewToolBar::PreviewTargetImage) || + (d->renderingPreviewMode == PreviewToolBar::NoPreviewMode)) { color = getSpotColor(TargetPreviewImage); emit spotPositionChangedFromTarget(color, d->spot); } else if (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVert) { - if (d->spot.x() > d->rect.width() / 2) + if (d->spot.x() > (d->rect.width() / 2)) { color = getSpotColor(TargetPreviewImage); emit spotPositionChangedFromTarget(color, QPoint(d->spot.x() - d->rect.width() / 2, d->spot.y())); } else { color = getSpotColor(OriginalImage); emit spotPositionChangedFromOriginal(color, d->spot); } } else if (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVertCont) { - if (d->spot.x() > d->rect.width() / 2) + if (d->spot.x() > (d->rect.width() / 2)) { color = getSpotColor(TargetPreviewImage); emit spotPositionChangedFromTarget(color, d->spot); } else { color = getSpotColor(OriginalImage); emit spotPositionChangedFromOriginal(color, d->spot); } } else if (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorz) { - if (d->spot.y() > d->rect.height() / 2) + if (d->spot.y() > (d->rect.height() / 2)) { color = getSpotColor(TargetPreviewImage); emit spotPositionChangedFromTarget(color, QPoint(d->spot.x(), d->spot.y() - d->rect.height() / 2)); } else { color = getSpotColor(OriginalImage); emit spotPositionChangedFromOriginal(color, d->spot); } } else if (d->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorzCont) { - if (d->spot.y() > d->rect.height() / 2) + if (d->spot.y() > (d->rect.height() / 2)) { color = getSpotColor(TargetPreviewImage); emit spotPositionChangedFromTarget(color, d->spot); } else { color = getSpotColor(OriginalImage); emit spotPositionChangedFromOriginal(color, d->spot); } } } else if (e->button() == Qt::LeftButton && d->drawingMask) { d->drawingMask = false; updatePreview(); } } } void ImageGuideWidget::mouseMoveEvent(QMouseEvent* e) { if (d->rect.contains(e->x(), e->y())) { - if (d->focus && d->spotVisible) + if (d->focus && d->spotVisible) { setCursor(Qt::CrossCursor); d->spot.setX(e->x() - d->rect.x()); d->spot.setY(e->y() - d->rect.y()); } else if (d->enableDrawMask) { setCursor(d->maskCursor); if ((e->buttons() & Qt::LeftButton) && d->drawingMask) { QPoint currentPos = QPoint(e->x() - d->rect.x(), e->y() - d->rect.y()); drawLineTo(currentPos); updatePreview(); } } } else { unsetCursor(); } } void ImageGuideWidget::enterEvent(QEvent*) { - if (!d->focus && d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) + if (!d->focus && (d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver)) { d->onMouseMovePreviewToggled = false; updatePixmap(); repaint(); } } void ImageGuideWidget::leaveEvent(QEvent*) { - if (!d->focus && d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) + if (!d->focus && (d->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver)) { d->onMouseMovePreviewToggled = true; updatePixmap(); update(); } } void ImageGuideWidget::setPoints(const QPolygon& p, bool drawLine) { d->selectedPoints = p; d->drawLineBetweenPoints = drawLine; updatePreview(); } void ImageGuideWidget::resetPoints() { d->selectedPoints.clear(); } void ImageGuideWidget::drawLineTo(const QPoint& endPoint) { drawLineTo(d->penWidth, d->eraseMask, d->paintColor, d->lastPoint, endPoint); } void ImageGuideWidget::drawLineTo(int width, bool erase, const QColor& color, const QPoint& start, const QPoint& end) { QPainter painter(d->maskPixmap); if (erase) { // drawLine() seems to ignore composition modes, use a tmp pixmap and combine it later on + QPixmap tmpMask(d->maskPixmap->width(), d->maskPixmap->height()); tmpMask.fill(Qt::transparent); QPainter tmpPainter(&tmpMask); painter.setRenderHint(QPainter::Antialiasing, false); painter.setCompositionMode(QPainter::CompositionMode_DestinationOut); QPen eraser; eraser.setColor(Qt::yellow); eraser.setStyle(Qt::SolidLine); eraser.setWidth(width); eraser.setCapStyle(Qt::RoundCap); eraser.setJoinStyle(Qt::RoundJoin); tmpPainter.setPen(eraser); tmpPainter.setBrush(QBrush()); tmpPainter.drawLine(start, end); tmpPainter.end(); painter.drawPixmap(0, 0, tmpMask); } else { painter.setPen(QPen(color, width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); painter.drawLine(start, end); } - int rad = (width / 2) + 2; + int rad = (width / 2) + 2; update(QRect(start, end).normalized().adjusted(-rad, -rad, +rad, +rad)); d->lastPoint = end; painter.end(); } void ImageGuideWidget::setPaintColor(const QColor& color) { d->paintColor = color; } void ImageGuideWidget::setMaskEnabled(bool enabled) { d->enableDrawMask = enabled; unsetCursor(); updatePreview(); } void ImageGuideWidget::setEraseMode(bool erase) { d->eraseMask = erase; } QImage ImageGuideWidget::getMask() const { QImage mask = d->maskPixmap->toImage(); return mask; } QPoint ImageGuideWidget::translatePointPosition(const QPoint& point) const { int x = d->rect.x() + 1 + (int)(point.x() * (float)d->preview.width() / (float)d->iface->originalSize().width()); int y = d->rect.y() + 1 + (int)(point.y() * (float)d->preview.height() / (float)d->iface->originalSize().height()); return (QPoint(x, y)); } void ImageGuideWidget::setMaskPenSize(int size) { d->penWidth = size; updateMaskCursor(); } void ImageGuideWidget::updateMaskCursor() { int size = d->penWidth; if (size > 64) { size = 64; } if (size < 3) { size = 3; } QPixmap pix(size, size); pix.fill(Qt::transparent); QPainter p(&pix); p.setRenderHint(QPainter::Antialiasing, true); p.drawEllipse(1, 1, size - 2, size - 2); d->maskCursor = QCursor(pix); } void ImageGuideWidget::setSpotPosition(const QPoint& point) { d->spot.setX(point.x()); d->spot.setY(point.y()); updatePreview(); } void ImageGuideWidget::updateSpotPosition(int x, int y) { QPoint origin = d->rect.topLeft(); - x -= origin.x(); - y -= origin.y(); + x -= origin.x(); + y -= origin.y(); d->spot.setX(x); d->spot.setY(y); updatePreview(); } QPoint ImageGuideWidget::translateItemPosition(const QPoint& point, bool src) const { int x = (int)(point.x() * (float)d->preview.width() / (float) d->iface->originalSize().width()); int y = (int)(point.y() * (float)d->preview.height() / (float) d->iface->originalSize().height()); if (!src) { x = (int)(point.x()); y = (int)(point.y()); x -= (int)(d->rect.topLeft().x()) + 1; y -= (int)(d->rect.topLeft().y()) + 1; } return (QPoint(x, y)); } void ImageGuideWidget::setMaskCursor() { if (d->enableDrawMask) { updateMaskCursor(); setCursor(d->maskCursor); updatePreview(); } } } // namespace Digikam diff --git a/core/utilities/imageeditor/widgets/imageguidewidget.h b/core/utilities/imageeditor/widgets/imageguidewidget.h index ce44f75a5a..bb1ee93d3a 100644 --- a/core/utilities/imageeditor/widgets/imageguidewidget.h +++ b/core/utilities/imageeditor/widgets/imageguidewidget.h @@ -1,143 +1,143 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2004-08-20 * Description : a widget to display an image with guides * * Copyright (C) 2004-2020 by Gilles Caulier * * 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, 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. * * ============================================================ */ #ifndef DIGIKAM_IMAGE_GUIDE_WIDGET_H #define DIGIKAM_IMAGE_GUIDE_WIDGET_H // Qt includes #include #include #include #include #include #include #include #include #include // Local includes #include "imageiface.h" #include "dcolor.h" #include "digikam_export.h" namespace Digikam { class DColor; class DIGIKAM_EXPORT ImageGuideWidget : public QWidget { Q_OBJECT public: enum GuideToolMode { HVGuideMode = 0, PickColorMode }; enum ColorPointSrc { OriginalImage = 0, PreviewImage, TargetPreviewImage }; public: explicit ImageGuideWidget(QWidget* const parent = nullptr, bool spotVisible = true, int guideMode = PickColorMode, const QColor& guideColor = Qt::red, int guideSize = 1, bool blink = false, ImageIface::PreviewType type= ImageIface::FullImage); ~ImageGuideWidget(); ImageIface* imageIface() const; QImage getMask() const; QPoint getSpotPosition() const; DColor getSpotColor(int getColorFrom) const; int previewMode() const; void setSpotVisible(bool spotVisible, bool blink = false); void setSpotVisibleNoUpdate(bool spotVisible); void resetSpotPosition(); void updatePreview(); void setPoints(const QPolygon& p, bool drawLine = false); void resetPoints(); void setPaintColor(const QColor& color); void setEraseMode(bool erase); void setMaskEnabled(bool enabled); void setMaskPenSize(int size); void setMaskCursor(); void setBackgroundColor(const QColor&); void ICCSettingsChanged(); void exposureSettingsChanged(); public Q_SLOTS: void slotChangeGuideColor(const QColor& color); void slotChangeGuideSize(int size); void slotPreviewModeChanged(int mode); Q_SIGNALS: void spotPositionChangedFromOriginal(const Digikam::DColor& color, const QPoint& position); void spotPositionChangedFromTarget(const Digikam::DColor& color, const QPoint& position); void signalResized(); protected: - void paintEvent(QPaintEvent*) override; - void resizeEvent(QResizeEvent*) override; - void timerEvent(QTimerEvent*) override; - void mousePressEvent(QMouseEvent*) override; - void mouseReleaseEvent(QMouseEvent*) override; - void mouseMoveEvent(QMouseEvent*) override; - void enterEvent(QEvent*) override; - void leaveEvent(QEvent*) override; + void paintEvent(QPaintEvent*) override; + void resizeEvent(QResizeEvent*) override; + void timerEvent(QTimerEvent*) override; + void mousePressEvent(QMouseEvent*) override; + void mouseReleaseEvent(QMouseEvent*) override; + void mouseMoveEvent(QMouseEvent*) override; + void enterEvent(QEvent*) override; + void leaveEvent(QEvent*) override; void updatePixmap(); void drawLineTo(const QPoint& endPoint); void drawLineTo(int width, bool erase, const QColor& color, const QPoint& start, const QPoint& end); QPoint translatePointPosition(const QPoint& point) const; void drawText(QPainter* const p, const QPoint& corner, const QString& text); void updateMaskCursor(); void setSpotPosition(const QPoint& point); void updateSpotPosition(int x, int y); QPoint translateItemPosition(const QPoint& point, bool src) const; private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_IMAGE_GUIDE_WIDGET_H diff --git a/core/utilities/imageeditor/widgets/imagepreviewitem.cpp b/core/utilities/imageeditor/widgets/imagepreviewitem.cpp index 1610bddcfc..e80ce66aae 100644 --- a/core/utilities/imageeditor/widgets/imagepreviewitem.cpp +++ b/core/utilities/imageeditor/widgets/imagepreviewitem.cpp @@ -1,162 +1,164 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2011-04-27 * Description : image preview item for image editor. * * Copyright (C) 2011-2020 by Gilles Caulier * * 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, 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. * * ============================================================ */ #include "imagepreviewitem.h" // Qt includes #include #include #include #include // Local includes #include "dimg.h" #include "exposurecontainer.h" #include "iccmanager.h" #include "iccsettingscontainer.h" #include "icctransform.h" #include "editorcore.h" #include "dimgitems_p.h" namespace Digikam { ImagePreviewItem::ImagePreviewItem() { Q_D(GraphicsDImgItem); d->init(this); } ImagePreviewItem::~ImagePreviewItem() { } void ImagePreviewItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { Q_D(GraphicsDImgItem); QRect drawRect = option->exposedRect.intersected(boundingRect()).toAlignedRect(); QRect pixSourceRect; QPixmap pix; QSize completeSize = boundingRect().size().toSize(); - /* For high resolution ("retina") displays, Mac OS X / Qt - report only half of the physical resolution in terms of - pixels, i.e. every logical pixels corresponds to 2x2 - physical pixels. However, UI elements and fonts are - nevertheless rendered at full resolution, and pixmaps - as well, provided their resolution is high enough (that - is, higher than the reported, logical resolution). - - To work around this, we render the photos not a logical - resolution, but with the photo's full resolution, but - at the screen's aspect ratio. When we later draw this - high resolution bitmap, it is up to Qt to scale the - photo to the true physical resolution. The ratio - computed below is the ratio between the photo and - screen resolutions, or equivalently the factor by which - we need to increase the pixel size of the rendered - pixmap. - */ + /* + * For high resolution ("retina") displays, Mac OS X / Qt + * report only half of the physical resolution in terms of + * pixels, i.e. every logical pixels corresponds to 2x2 + * physical pixels. However, UI elements and fonts are + * nevertheless rendered at full resolution, and pixmaps + * as well, provided their resolution is high enough (that + * is, higher than the reported, logical resolution). + * + * To work around this, we render the photos not a logical + * resolution, but with the photo's full resolution, but + * at the screen's aspect ratio. When we later draw this + * high resolution bitmap, it is up to Qt to scale the + * photo to the true physical resolution. The ratio + * computed below is the ratio between the photo and + * screen resolutions, or equivalently the factor by which + * we need to increase the pixel size of the rendered + * pixmap. + */ double ratio = qApp->devicePixelRatio(); QRect scaledDrawRect = QRectF(ratio * drawRect.x(), ratio * drawRect.y(), ratio * drawRect.width(), ratio * drawRect.height()).toRect(); // scale "as if" scaling to whole image, but clip output to our exposed region + QSize scaledCompleteSize = QSizeF(ratio * completeSize.width(), ratio * completeSize.height()).toSize(); DImg scaledImage = d->image.smoothScaleClipped(scaledCompleteSize.width(), scaledCompleteSize.height(), scaledDrawRect.x(), scaledDrawRect.y(), scaledDrawRect.width(), scaledDrawRect.height()); if (d->cachedPixmaps.find(scaledDrawRect, &pix, &pixSourceRect)) { if (pixSourceRect.isNull()) { painter->drawPixmap(drawRect, pix); } else { painter->drawPixmap(drawRect, pix, pixSourceRect); } } else { // TODO: factoring ICC settings code using ImageIface/EditorCore methods. // Apply CM settings. bool doSoftProofing = EditorCore::defaultInstance()->softProofingEnabled(); ICCSettingsContainer iccSettings = EditorCore::defaultInstance()->getICCSettings(); if (iccSettings.enableCM && (iccSettings.useManagedView || doSoftProofing)) { IccManager manager(scaledImage); IccTransform monitorICCtrans; if (doSoftProofing) { monitorICCtrans = manager.displaySoftProofingTransform(IccProfile(iccSettings.defaultProofProfile), widget); } else { monitorICCtrans = manager.displayTransform(widget); } pix = scaledImage.convertToPixmap(monitorICCtrans); } else { pix = scaledImage.convertToPixmap(); } d->cachedPixmaps.insert(scaledDrawRect, pix); painter->drawPixmap(drawRect, pix); } // Show the Over/Under exposure pixels indicators ExposureSettingsContainer* const expoSettings = EditorCore::defaultInstance()->getExposureSettings(); if (expoSettings) { if (expoSettings->underExposureIndicator || expoSettings->overExposureIndicator) { QImage pureColorMask = scaledImage.pureColorMask(expoSettings); QPixmap pixMask = QPixmap::fromImage(pureColorMask); painter->drawPixmap(drawRect, pixMask); } } } } // namespace Digikam diff --git a/core/utilities/imageeditor/widgets/imageregionitem.cpp b/core/utilities/imageeditor/widgets/imageregionitem.cpp index ed966c5275..9f985789b8 100644 --- a/core/utilities/imageeditor/widgets/imageregionitem.cpp +++ b/core/utilities/imageeditor/widgets/imageregionitem.cpp @@ -1,342 +1,345 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2013-07-25 * Description : image region widget item for image editor. * * Copyright (C) 2013-2014 by Yiou Wang * Copyright (C) 2013-2020 by Gilles Caulier * * 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, 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. * * ============================================================ */ #include "imageregionitem.h" // Qt includes #include #include // KDE includes #include // Local includes #include "digikam_debug.h" #include "dimgitems_p.h" #include "editorcore.h" #include "exposurecontainer.h" #include "iccmanager.h" #include "icctransform.h" #include "iccsettingscontainer.h" #include "imageiface.h" #include "previewtoolbar.h" namespace Digikam { class Q_DECL_HIDDEN ImageRegionItem::Private { public: explicit Private() : paintExtras(true), onMouseMovePreviewToggled(true), renderingPreviewMode(PreviewToolBar::PreviewBothImagesVertCont), view(nullptr), iface(nullptr) { } bool paintExtras; bool onMouseMovePreviewToggled; int renderingPreviewMode; - QPixmap targetPix; // Pixmap of target region to render for paint method. + QPixmap targetPix; ///< Pixmap of target region to render for paint method. QRect drawRect; QPolygon hightlightPoints; ImageRegionWidget* view; ImageIface* iface; }; ImageRegionItem::ImageRegionItem(ImageRegionWidget* const widget, bool paintExtras) : d_ptr(new Private) { d_ptr->view = widget; d_ptr->iface = new ImageIface; d_ptr->paintExtras = paintExtras; setAcceptHoverEvents(true); setImage(d_ptr->iface->original() ? d_ptr->iface->original()->copy() : DImg()); } ImageRegionItem::~ImageRegionItem() { delete d_ptr->iface; delete d_ptr; } QRect ImageRegionItem::getImageRegion() const { return d_ptr->drawRect; } void ImageRegionItem::setTargetImage(DImg& img) { d_ptr->targetPix = d_ptr->iface->convertToPixmap(img); update(); } void ImageRegionItem::setRenderingPreviewMode(int mode) { d_ptr->renderingPreviewMode = mode; update(); } void ImageRegionItem::setHighLightPoints(const QPolygon& pointsList) { d_ptr->hightlightPoints = pointsList; } void ImageRegionItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { Q_D(GraphicsDImgItem); d_ptr->drawRect = option->exposedRect.intersected(boundingRect()).toAlignedRect(); QRect pixSourceRect; QPixmap pix; QSize completeSize = boundingRect().size().toSize(); // scale "as if" scaling to whole image, but clip output to our exposed region + DImg scaledImage = d->image.smoothScaleClipped(completeSize.width(), completeSize.height(), d_ptr->drawRect.x(), d_ptr->drawRect.y(), d_ptr->drawRect.width(), d_ptr->drawRect.height()); if (d->cachedPixmaps.find(d_ptr->drawRect, &pix, &pixSourceRect)) { if (pixSourceRect.isNull()) { painter->drawPixmap(d_ptr->drawRect.topLeft(), pix); } else { painter->drawPixmap(d_ptr->drawRect.topLeft(), pix, pixSourceRect); } } else { // TODO: factoring ICC settings code using ImageIface/EditorCore methods. // Apply CM settings. bool doSoftProofing = EditorCore::defaultInstance()->softProofingEnabled(); ICCSettingsContainer iccSettings = EditorCore::defaultInstance()->getICCSettings(); if (iccSettings.enableCM && (iccSettings.useManagedView || doSoftProofing)) { IccManager manager(scaledImage); IccTransform monitorICCtrans; if (doSoftProofing) { monitorICCtrans = manager.displaySoftProofingTransform(IccProfile(iccSettings.defaultProofProfile), widget); } else { monitorICCtrans = manager.displayTransform(widget); } pix = scaledImage.convertToPixmap(monitorICCtrans); } else { pix = scaledImage.convertToPixmap(); } d->cachedPixmaps.insert(d_ptr->drawRect, pix); painter->drawPixmap(d_ptr->drawRect.topLeft(), pix); } if (d_ptr->paintExtras) { paintExtraData(painter); } // Show the Over/Under exposure pixels indicators ExposureSettingsContainer* const expoSettings = EditorCore::defaultInstance()->getExposureSettings(); if (expoSettings) { if (expoSettings->underExposureIndicator || expoSettings->overExposureIndicator) { QImage pureColorMask = scaledImage.pureColorMask(expoSettings); QPixmap pixMask = QPixmap::fromImage(pureColorMask); painter->drawPixmap(d_ptr->drawRect.topLeft(), pixMask); } } } void ImageRegionItem::paintExtraData(QPainter* const p) { QRect viewportRect = boundingRect().toAlignedRect(); QRect fontRectBefore = p->fontMetrics().boundingRect(viewportRect, 0, i18n("Before")); QRect fontRectAfter = p->fontMetrics().boundingRect(viewportRect, 0, i18n("After")); p->setRenderHint(QPainter::Antialiasing, true); p->setBackgroundMode(Qt::TransparentMode); - if (d_ptr->renderingPreviewMode == PreviewToolBar::PreviewOriginalImage || - (d_ptr->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver && !d_ptr->onMouseMovePreviewToggled)) + if ((d_ptr->renderingPreviewMode == PreviewToolBar::PreviewOriginalImage) || + ((d_ptr->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) && !d_ptr->onMouseMovePreviewToggled)) { d_ptr->view->drawText(p, QRectF(QPointF(d_ptr->drawRect.topLeft().x() + 20, d_ptr->drawRect.topLeft().y() + 20), fontRectBefore.size()), i18n("Before")); } - else if (d_ptr->renderingPreviewMode == PreviewToolBar::PreviewTargetImage || - d_ptr->renderingPreviewMode == PreviewToolBar::NoPreviewMode || - (d_ptr->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver && d_ptr->onMouseMovePreviewToggled)) + else if ((d_ptr->renderingPreviewMode == PreviewToolBar::PreviewTargetImage) || + (d_ptr->renderingPreviewMode == PreviewToolBar::NoPreviewMode) || + ((d_ptr->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) && d_ptr->onMouseMovePreviewToggled)) { p->drawPixmap(d_ptr->drawRect.x(), d_ptr->drawRect.y(), d_ptr->targetPix, 0, 0, d_ptr->drawRect.width(), d_ptr->drawRect.height()); - if (d_ptr->renderingPreviewMode == PreviewToolBar::PreviewTargetImage || - d_ptr->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) + if ((d_ptr->renderingPreviewMode == PreviewToolBar::PreviewTargetImage) || + (d_ptr->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver)) { d_ptr->view->drawText(p, QRectF(QPointF(d_ptr->drawRect.topLeft().x() + 20, d_ptr->drawRect.topLeft().y() + 20), fontRectAfter.size()), i18n("After")); } } - else if (d_ptr->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVert || - d_ptr->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVertCont) + else if ((d_ptr->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVert) || + (d_ptr->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVertCont)) { if (d_ptr->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVert) { p->drawPixmap(d_ptr->drawRect.x() + d_ptr->drawRect.width() / 2, d_ptr->drawRect.y(), d_ptr->targetPix, 0, 0, d_ptr->drawRect.width()/2, d_ptr->drawRect.height()); } if (d_ptr->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVertCont) { p->drawPixmap(d_ptr->drawRect.x() + d_ptr->drawRect.width() / 2, d_ptr->drawRect.y(), d_ptr->targetPix, d_ptr->drawRect.width()/2, 0, d_ptr->drawRect.width(), d_ptr->drawRect.height()); } p->setPen(QPen(Qt::white, 2, Qt::SolidLine)); p->drawLine(d_ptr->drawRect.topLeft().x() + d_ptr->drawRect.width()/2, d_ptr->drawRect.topLeft().y(), d_ptr->drawRect.topLeft().x() + d_ptr->drawRect.width()/2, d_ptr->drawRect.bottomLeft().y()); p->setPen(QPen(Qt::red, 2, Qt::DotLine)); p->drawLine(d_ptr->drawRect.topLeft().x() + d_ptr->drawRect.width()/2, d_ptr->drawRect.topLeft().y(), d_ptr->drawRect.topLeft().x() + d_ptr->drawRect.width()/2, d_ptr->drawRect.bottomLeft().y()); d_ptr->view->drawText(p, QRectF(QPointF(d_ptr->drawRect.topLeft().x() + 20, d_ptr->drawRect.topLeft().y() + 20), fontRectBefore.size()), i18n("Before")); d_ptr->view->drawText(p, QRectF(QPointF(d_ptr->drawRect.topLeft().x() + d_ptr->drawRect.width()/2 + 20, d_ptr->drawRect.topLeft().y() + 20), fontRectAfter.size()), i18n("After")); } - else if (d_ptr->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorz || - d_ptr->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorzCont) + else if ((d_ptr->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorz) || + (d_ptr->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorzCont)) { if (d_ptr->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorz) { p->drawPixmap(d_ptr->drawRect.x(), d_ptr->drawRect.y() + d_ptr->drawRect.height() / 2, d_ptr->targetPix, 0, 0, d_ptr->drawRect.width(), d_ptr->drawRect.height()/2); } if (d_ptr->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorzCont) { p->drawPixmap(d_ptr->drawRect.x(), d_ptr->drawRect.y() + d_ptr->drawRect.height() / 2, d_ptr->targetPix, 0, d_ptr->drawRect.height()/2, d_ptr->drawRect.width(), d_ptr->drawRect.height()); } p->setPen(QPen(Qt::white, 2, Qt::SolidLine)); p->drawLine(d_ptr->drawRect.topLeft().x() + 1, d_ptr->drawRect.topLeft().y() + d_ptr->drawRect.height()/2, d_ptr->drawRect.topRight().x() - 1, d_ptr->drawRect.topLeft().y() + d_ptr->drawRect.height()/2); p->setPen(QPen(Qt::red, 2, Qt::DotLine)); p->drawLine(d_ptr->drawRect.topLeft().x() + 1, d_ptr->drawRect.topLeft().y() + d_ptr->drawRect.height()/2, d_ptr->drawRect.topRight().x() - 1, d_ptr->drawRect.topLeft().y() + d_ptr->drawRect.height()/2); d_ptr->view->drawText(p, QRectF(QPointF(d_ptr->drawRect.topLeft().x() + 20, d_ptr->drawRect.topLeft().y() + 20), fontRectBefore.size()), i18n("Before")); d_ptr->view->drawText(p, QRectF(QPointF(d_ptr->drawRect.topLeft().x() + 20, d_ptr->drawRect.topLeft().y() + d_ptr->drawRect.height()/2 + 20), fontRectAfter.size()), i18n("After")); } // Drawing highlighted points. if (!d_ptr->hightlightPoints.isEmpty()) { QPoint pt; QRectF hpArea; for (int i = 0 ; i < d_ptr->hightlightPoints.count() ; ++i) { pt = d_ptr->hightlightPoints.point(i); double zoomFactor = zoomSettings()->realZoomFactor(); int x = (int)((double)pt.x() * zoomFactor); int y = (int)((double)pt.y() * zoomFactor); // Check if zoomed point is inside, not actual point + if (d_ptr->drawRect.contains(QPoint(x,y))) { - - //QPoint hp(contentsToViewport(QPointF(x, y))); +/* + QPoint hp(contentsToViewport(QPointF(x, y))); +*/ QPointF hp(mapToScene(QPointF(x, y))); hpArea.setSize(QSize((int)(16 * zoomFactor), (int)(16 * zoomFactor))); hpArea.moveCenter(hp); p->setPen(QPen(Qt::white, 2, Qt::SolidLine)); p->drawLine(hp.x(), hpArea.y(), hp.x(), hp.y() - (int)(3 * zoomFactor)); p->drawLine(hp.x(), hp.y() + (int)(3 * zoomFactor), hp.x(), hpArea.bottom()); p->drawLine(hpArea.x(), hp.y(), hp.x() - (int)(3 * zoomFactor), hp.y()); p->drawLine(hp.x() + (int)(3 * zoomFactor), hp.y(), hpArea.right(), hp.y()); p->setPen(QPen(Qt::red, 2, Qt::DotLine)); p->drawLine(hp.x(), hpArea.y(), hp.x(), hp.y() - (int)(3 * zoomFactor)); p->drawLine(hp.x(), hp.y() + (int)(3 * zoomFactor), hp.x(), hpArea.bottom()); p->drawLine(hpArea.x(), hp.y(), hp.x() - (int)(3 * zoomFactor), hp.y()); p->drawLine(hp.x() + (int)(3 * zoomFactor), hp.y(), hpArea.right(), hp.y()); } } } } void ImageRegionItem::hoverEnterEvent(QGraphicsSceneHoverEvent*) { d_ptr->onMouseMovePreviewToggled = false; update(); } void ImageRegionItem::hoverLeaveEvent(QGraphicsSceneHoverEvent*) { d_ptr->onMouseMovePreviewToggled = true; update(); } } // namespace Digikam diff --git a/core/utilities/imageeditor/widgets/imageregionitem.h b/core/utilities/imageeditor/widgets/imageregionitem.h index 8c20f918f8..7d22f62fff 100644 --- a/core/utilities/imageeditor/widgets/imageregionitem.h +++ b/core/utilities/imageeditor/widgets/imageregionitem.h @@ -1,70 +1,70 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2013-07-25 * Description : image region widget item for image editor. * * Copyright (C) 2013-2014 by Yiou Wang * Copyright (C) 2013-2020 by Gilles Caulier * * * 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, 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. * * ============================================================ */ #ifndef DIGIKAM_IMAGE_REGION_ITEM_H #define DIGIKAM_IMAGE_REGION_ITEM_H // Qt includes #include // Local includes #include "graphicsdimgitem.h" #include "digikam_export.h" #include "dimg.h" #include "imageregionwidget.h" namespace Digikam { class DIGIKAM_EXPORT ImageRegionItem : public GraphicsDImgItem { public: explicit ImageRegionItem(ImageRegionWidget* const view, bool paintExtras = true); virtual ~ImageRegionItem(); void setTargetImage(DImg& img); void setHighLightPoints(const QPolygon& pointsList); void setRenderingPreviewMode(int mode); void paintExtraData(QPainter* const painter); QRect getImageRegion() const; void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override; - void hoverEnterEvent(QGraphicsSceneHoverEvent*) override; - void hoverLeaveEvent(QGraphicsSceneHoverEvent*) override; + void hoverEnterEvent(QGraphicsSceneHoverEvent*) override; + void hoverLeaveEvent(QGraphicsSceneHoverEvent*) override; private: class Private; Private* const d_ptr; }; } // namespace Digikam #endif // DIGIKAM_IMAGE_REGION_ITEM_H diff --git a/core/utilities/imageeditor/widgets/imageregionwidget.cpp b/core/utilities/imageeditor/widgets/imageregionwidget.cpp index 8a76587c24..519042c2bd 100644 --- a/core/utilities/imageeditor/widgets/imageregionwidget.cpp +++ b/core/utilities/imageeditor/widgets/imageregionwidget.cpp @@ -1,265 +1,266 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2013-07-15 * Description : a widget to draw an image clip region. * * Copyright (C) 2013-2014 by Yiou Wang * Copyright (C) 2010-2012 by Marcel Wiesweg * Copyright (C) 2011-2020 by Gilles Caulier * * 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, 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. * * ============================================================ */ #include "imageregionwidget.h" // C++ includes #include // Qt includes #include #include // KDE includes #include // Local includes #include "digikam_debug.h" #include "imageregionitem.h" #include "previewtoolbar.h" #include "previewlayout.h" #include "dimgitems_p.h" namespace Digikam { class Q_DECL_HIDDEN ImageRegionWidget::Private { public: explicit Private() : capturePtMode(false), renderingPreviewMode(PreviewToolBar::PreviewBothImagesVertCont), oldRenderingPreviewMode(PreviewToolBar::PreviewBothImagesVertCont), delay(nullptr), item(nullptr) { } bool capturePtMode; int renderingPreviewMode; int oldRenderingPreviewMode; QPolygon hightlightPoints; QTimer* delay; ImageRegionItem* item; }; ImageRegionWidget::ImageRegionWidget(QWidget* const parent, bool paintExtras) : GraphicsDImgView(parent), d_ptr(new Private) { d_ptr->item = new ImageRegionItem(this, paintExtras); setItem(d_ptr->item); setAttribute(Qt::WA_DeleteOnClose); setFrameStyle(QFrame::NoFrame); setMinimumSize(480, 320); setWhatsThis(i18n("

Here you can see the original clip image " "which will be used for the preview computation.

" "

Click and drag the mouse cursor in the " "image to change the clip focus.

")); d_ptr->delay = new QTimer(this); d_ptr->delay->setInterval(500); d_ptr->delay->setSingleShot(true); connect(d_ptr->delay, SIGNAL(timeout()), this, SLOT(slotOriginalImageRegionChanged())); connect(this, SIGNAL(viewportRectChanged(QRectF)), this, SLOT(slotOriginalImageRegionChangedDelayed())); layout()->fitToWindow(); installPanIcon(); } ImageRegionWidget::~ImageRegionWidget() { delete d_ptr->item; delete d_ptr; } void ImageRegionWidget::setHighLightPoints(const QPolygon& pointsList) { d_ptr->item->setHighLightPoints(pointsList); viewport()->update(); } void ImageRegionWidget::setCapturePointMode(bool b) { if (d_ptr->capturePtMode && b) { return; } d_ptr->capturePtMode = b; viewport()->setMouseTracking(!b); if (b) { d_ptr->oldRenderingPreviewMode = d_ptr->renderingPreviewMode; slotPreviewModeChanged(PreviewToolBar::PreviewOriginalImage); viewport()->setCursor(QCursor(QIcon::fromTheme(QLatin1String("color-picker")).pixmap(32), -27, 5)); } else { slotPreviewModeChanged(d_ptr->oldRenderingPreviewMode); viewport()->unsetCursor(); } } void ImageRegionWidget::slotPreviewModeChanged(int mode) { d_ptr->renderingPreviewMode = mode; d_ptr->item->setRenderingPreviewMode(mode); slotOriginalImageRegionChanged(); viewport()->update(); } QRect ImageRegionWidget::getOriginalImageRegionToRender() const { QRect r = d_ptr->item->getImageRegion(); double z = layout()->realZoomFactor(); int x = qRound((double)r.x() / z); int y = qRound((double)r.y() / z); int w = qRound((double)r.width() / z); int h = qRound((double)r.height() / z); QRect rect(x, y, w, h); return (rect); } void ImageRegionWidget::setPreviewImage(const DImg& img) { DImg image = img; QRect r = d_ptr->item->getImageRegion(); image.resize(r.width(), r.height()); // Because tool which only work on image data, the DImg container // do not contain metadata from original image. About Color Managed View, we need to // restore the embedded ICC color profile. // However, some tools may set a profile on the preview image, which we accept of course. + if (image.getIccProfile().isNull()) { image.setIccProfile(d_ptr->item->image().getIccProfile()); } d_ptr->item->setTargetImage(image); } DImg ImageRegionWidget::getOriginalImage() const { return (d_ptr->item->image().copy()); } DImg ImageRegionWidget::getOriginalRegionImage(bool useDownscaledImage) const { DImg image = d_ptr->item->image().copy(getOriginalImageRegionToRender()); if (useDownscaledImage) { QRect r = d_ptr->item->getImageRegion(); image.resize(r.width(), r.height()); } return (image); } void ImageRegionWidget::slotOriginalImageRegionChangedDelayed() { viewport()->update(); d_ptr->delay->start(); } void ImageRegionWidget::slotOriginalImageRegionChanged(bool targetDone) { if (targetDone) { emit signalOriginalClipFocusChanged(); // For Image Edit Tools } } void ImageRegionWidget::exposureSettingsChanged() { d_ptr->item->clearCache(); viewport()->update(); } void ImageRegionWidget::ICCSettingsChanged() { d_ptr->item->clearCache(); viewport()->update(); } void ImageRegionWidget::mousePressEvent(QMouseEvent* e) { if (d_ptr->capturePtMode) { emitCapturedPointFromOriginal(mapToScene(e->pos())); QGraphicsView::mousePressEvent(e); return; } GraphicsDImgView::mousePressEvent(e); } void ImageRegionWidget::mouseReleaseEvent(QMouseEvent* e) { if (d_ptr->capturePtMode) { setCapturePointMode(false); QGraphicsView::mouseReleaseEvent(e); return; } GraphicsDImgView::mouseReleaseEvent(e); } void ImageRegionWidget::emitCapturedPointFromOriginal(const QPointF& pt) { int x = (int)(pt.x() / layout()->realZoomFactor()); int y = (int)(pt.y() / layout()->realZoomFactor()); QPoint imgPt(x, y); DColor color = d_ptr->item->image().getPixelColor(x, y); qCDebug(DIGIKAM_GENERAL_LOG) << "Captured point from image : " << imgPt; emit signalCapturedPointFromOriginal(color, imgPt); } void ImageRegionWidget::updateImage(const DImg& img) { d_ptr->item->setImage(img); } } // namespace Digikam diff --git a/core/utilities/imageeditor/widgets/imageregionwidget.h b/core/utilities/imageeditor/widgets/imageregionwidget.h index f77d29be4b..75b5dd3e43 100644 --- a/core/utilities/imageeditor/widgets/imageregionwidget.h +++ b/core/utilities/imageeditor/widgets/imageregionwidget.h @@ -1,114 +1,116 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2013-07-15 * Description : a widget to draw an image clip region. * * Copyright (C) 2013-2014 by Yiou Wang * Copyright (C) 2010-2012 by Marcel Wiesweg * Copyright (C) 2011-2020 by Gilles Caulier * * 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, 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. * * ============================================================ */ #ifndef DIGIKAM_IMAGE_REGION_WIDGET_H #define DIGIKAM_IMAGE_REGION_WIDGET_H // Qt includes #include #include #include #include #include #include #include // Local includes #include "dimg.h" #include "graphicsdimgview.h" #include "imagezoomsettings.h" #include "digikam_export.h" namespace Digikam { class DIGIKAM_EXPORT ImageRegionWidget : public GraphicsDImgView { Q_OBJECT public: explicit ImageRegionWidget(QWidget* const parent = nullptr, bool paintExtras = true); ~ImageRegionWidget(); - /** To get target image region area to render. + /** + * To get target image region area to render. */ QRect getOriginalImageRegionToRender() const; - /** To get target image region image to use for render operations - If the bool parameter is true a downscaled version of the image - region at screen resolution will be sent. - Should be use to increase preview speed for the effects whose - behaviour is a function of each pixel. + /** + * To get target image region image to use for render operations + * If the bool parameter is true a downscaled version of the image + * region at screen resolution will be sent. + * Should be use to increase preview speed for the effects whose + * behaviour is a function of each pixel. */ DImg getOriginalRegionImage(bool useDownscaledImage = false) const; DImg getOriginalImage() const; void setPreviewImage(const DImg& img); void updateImage(const DImg& img); void setCapturePointMode(bool b); bool capturePointMode() const; void setHighLightPoints(const QPolygon& pointsList); void ICCSettingsChanged(); void exposureSettingsChanged(); Q_SIGNALS: void signalOriginalClipFocusChanged(); void signalCapturedPointFromOriginal(const Digikam::DColor&, const QPoint&); public Q_SLOTS: void slotPreviewModeChanged(int mode); void slotOriginalImageRegionChanged(bool targetDone=true); protected: void mousePressEvent(QMouseEvent*) override; void mouseReleaseEvent(QMouseEvent*) override; private: void emitCapturedPointFromOriginal(const QPointF&); private Q_SLOTS: void slotOriginalImageRegionChangedDelayed(); private: class Private; Private* const d_ptr; }; } // namespace Digikam #endif // DIGIKAM_IMAGE_REGION_WIDGET_H diff --git a/core/utilities/imageeditor/widgets/previewlist.cpp b/core/utilities/imageeditor/widgets/previewlist.cpp index 14beaebb75..d940eec05f 100644 --- a/core/utilities/imageeditor/widgets/previewlist.cpp +++ b/core/utilities/imageeditor/widgets/previewlist.cpp @@ -1,425 +1,435 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2010-02-13 * Description : a list of selectable options with preview * effects as thumbnails. * * Copyright (C) 2010-2020 by Gilles Caulier * * 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, 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. * * ============================================================ */ #include "previewlist.h" // Qt includes #include #include #include #include // KDE includes #include // Local includes #include "dimg.h" #include "dimgthreadedfilter.h" #include "imageiface.h" #include "digikam_debug.h" #include "dlayoutbox.h" #include "dworkingpixmap.h" namespace Digikam { class Q_DECL_HIDDEN PreviewThreadWrapper::Private { public: explicit Private() { } QMap map; }; PreviewThreadWrapper::PreviewThreadWrapper(QObject* const parent) : QObject(parent), d(new Private) { } PreviewThreadWrapper::~PreviewThreadWrapper() { qDeleteAll(d->map.values()); d->map.clear(); delete d; } void PreviewThreadWrapper::registerFilter(int id, DImgThreadedFilter* const filter) { if (d->map.contains(id)) + { return; + } filter->setParent(this); d->map.insert(id, filter); connect(filter, SIGNAL(started()), this, SLOT(slotFilterStarted())); connect(filter, SIGNAL(finished(bool)), this, SLOT(slotFilterFinished(bool))); connect(filter, SIGNAL(progress(int)), this, SLOT(slotFilterProgress(int))); } void PreviewThreadWrapper::slotFilterStarted() { DImgThreadedFilter* const filter = dynamic_cast(sender()); if (!filter) { return; } emit signalFilterStarted(d->map.key(filter)); } void PreviewThreadWrapper::slotFilterFinished(bool success) { DImgThreadedFilter* const filter = dynamic_cast(sender()); if (!filter) { return; } if (success) { int key = d->map.key(filter); QPixmap pix = filter->getTargetImage().smoothScale(128, 128, Qt::KeepAspectRatio).convertToPixmap(); emit signalFilterFinished(key, pix); } } void PreviewThreadWrapper::slotFilterProgress(int /*progress*/) { DImgThreadedFilter* const filter = dynamic_cast(sender()); if (!filter) { return; } //qCDebug(DIGIKAM_GENERAL_LOG) << filter->filterName() << " : " << progress << " %"; } void PreviewThreadWrapper::startFilters() { foreach (DImgThreadedFilter* const filter, d->map) { filter->startFilter(); } } void PreviewThreadWrapper::stopFilters() { foreach (DImgThreadedFilter* const filter, d->map) { filter->cancelFilter(); filter->deleteLater(); } } // --------------------------------------------------------------------- class Q_DECL_HIDDEN PreviewListItem::Private { public: explicit Private() : busy(false), id(0) { } bool busy; int id; }; PreviewListItem::PreviewListItem(QListWidget* const parent) : QListWidgetItem(parent), d(new Private) { } PreviewListItem::~PreviewListItem() { delete d; } void PreviewListItem::setPixmap(const QPixmap& pix) { QIcon icon = QIcon(pix); + // We make sure the preview icon stays the same regardless of the role + icon.addPixmap(pix, QIcon::Selected, QIcon::On); icon.addPixmap(pix, QIcon::Selected, QIcon::Off); icon.addPixmap(pix, QIcon::Active, QIcon::On); icon.addPixmap(pix, QIcon::Active, QIcon::Off); icon.addPixmap(pix, QIcon::Normal, QIcon::On); icon.addPixmap(pix, QIcon::Normal, QIcon::Off); setIcon(icon); } void PreviewListItem::setId(int id) { d->id = id; } int PreviewListItem::id() const { return d->id; } void PreviewListItem::setBusy(bool b) { d->busy = b; } bool PreviewListItem::isBusy() const { return d->busy; } // --------------------------------------------------------------------- class Q_DECL_HIDDEN PreviewList::Private { public: explicit Private() : progressCount(0), progressTimer(nullptr), + progressPix(DWorkingPixmap()), wrapper(nullptr) { - progressPix = DWorkingPixmap(); } - int progressCount; + int progressCount; - QTimer* progressTimer; + QTimer* progressTimer; - DWorkingPixmap progressPix; + DWorkingPixmap progressPix; - PreviewThreadWrapper* wrapper; + PreviewThreadWrapper* wrapper; }; PreviewList::PreviewList(QObject* const /*parent*/) : QListWidget(), d(new Private) { d->wrapper = new PreviewThreadWrapper(this); setSelectionMode(QAbstractItemView::SingleSelection); setDropIndicatorShown(true); setSortingEnabled(false); setIconSize(QSize(96, 96)); setViewMode(QListView::IconMode); setWrapping(true); setWordWrap(false); setMovement(QListView::Static); setSpacing(5); setGridSize(QSize(125, 100 + fontMetrics().height())); setResizeMode(QListView::Adjust); setTextElideMode(Qt::ElideRight); setCursor(Qt::PointingHandCursor); setStyleSheet(QLatin1String("QListWidget::item:selected:!active {show-decoration-selected: 0}")); d->progressTimer = new QTimer(this); d->progressTimer->setInterval(300); connect(d->progressTimer, SIGNAL(timeout()), this, SLOT(slotProgressTimerDone())); connect(d->wrapper, SIGNAL(signalFilterStarted(int)), this, SLOT(slotFilterStarted(int))); connect(d->wrapper, SIGNAL(signalFilterFinished(int,QPixmap)), this, SLOT(slotFilterFinished(int,QPixmap))); } PreviewList::~PreviewList() { stopFilters(); delete d; } void PreviewList::startFilters() { d->progressTimer->start(); d->wrapper->startFilters(); } void PreviewList::stopFilters() { d->progressTimer->stop(); d->wrapper->stopFilters(); } PreviewListItem* PreviewList::addItem(DImgThreadedFilter* const filter, const QString& txt, int id) { if (!filter) { return nullptr; } d->wrapper->registerFilter(id, filter); PreviewListItem* const item = new PreviewListItem(this); item->setText(txt); + // in case text is mangled by textelide, it is displayed by hovering. + item->setToolTip(txt); item->setId(id); + return item; } PreviewListItem* PreviewList::findItem(int id) const { int it = 0; while (it <= this->count()) { PreviewListItem* const item = dynamic_cast(this->item(it)); - if (item && item->id() == id) + if (item && (item->id() == id)) { return item; } ++it; } return nullptr; } void PreviewList::setCurrentId(int id) { int it = 0; while (it <= this->count()) { PreviewListItem* const item = dynamic_cast(this->item(it)); - if (item && item->id() == id) + if (item && (item->id() == id)) { setCurrentItem(item); item->setSelected(true); + return; } ++it; } } int PreviewList::currentId() const { PreviewListItem* const item = dynamic_cast(currentItem()); if (item) { return item->id(); } return 0; } void PreviewList::slotProgressTimerDone() { QPixmap ppix(d->progressPix.frameAt(d->progressCount)); QPixmap pixmap(128, 128); pixmap.fill(Qt::transparent); QPainter p(&pixmap); p.drawPixmap((pixmap.width() / 2) - (ppix.width() / 2), (pixmap.height() / 2) - (ppix.height() / 2), ppix); int busy = 0; int it = 0; PreviewListItem* selectedItem = nullptr; while (it <= this->count()) { PreviewListItem* const item = dynamic_cast(this->item(it)); if (item && item->isSelected()) { selectedItem = item; } if (item && item->isBusy()) { item->setPixmap(pixmap); ++busy; } ++it; } d->progressCount++; if (d->progressCount >= d->progressPix.frameCount()) { d->progressCount = 0; } if (!busy) { d->progressTimer->stop(); + // Qt 4.5 doesn't display icons correctly centred over i18n(text), // Qt 4.6 doesn't even reset the previous selection correctly. + this->reset(); if (selectedItem) { setCurrentItem(selectedItem); } } } void PreviewList::slotFilterStarted(int id) { PreviewListItem* const item = findItem(id); item->setBusy(true); } void PreviewList::slotFilterFinished(int id, const QPixmap& pix) { PreviewListItem* const item = findItem(id); if (item) { item->setBusy(false); item->setPixmap(pix); update(); } } } // namespace Digikam diff --git a/core/utilities/imageeditor/widgets/previewtoolbar.cpp b/core/utilities/imageeditor/widgets/previewtoolbar.cpp index a2e3676388..ad38d07170 100644 --- a/core/utilities/imageeditor/widgets/previewtoolbar.cpp +++ b/core/utilities/imageeditor/widgets/previewtoolbar.cpp @@ -1,317 +1,323 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2010-01-10 * Description : a tool bar for preview mode * * Copyright (C) 2010-2020 by Gilles Caulier * * 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, 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. * * ============================================================ */ #include "previewtoolbar.h" // Qt includes #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "editorwindow.h" namespace Digikam { class Q_DECL_HIDDEN PreviewToolBar::Private { public: explicit Private() : previewOriginalButton(nullptr), previewBothButtonVert(nullptr), previewBothButtonHorz(nullptr), previewDuplicateBothButtonVert(nullptr), previewDupplicateBothButtonHorz(nullptr), previewtargetButton(nullptr), previewToggleMouseOverButton(nullptr), previewButtons(nullptr), actionsGroup(nullptr), actionsMenu(nullptr) { } QToolButton* previewOriginalButton; QToolButton* previewBothButtonVert; QToolButton* previewBothButtonHorz; QToolButton* previewDuplicateBothButtonVert; QToolButton* previewDupplicateBothButtonHorz; QToolButton* previewtargetButton; QToolButton* previewToggleMouseOverButton; QButtonGroup* previewButtons; QActionGroup* actionsGroup; QMenu* actionsMenu; }; PreviewToolBar::PreviewToolBar(QWidget* const parent) : QWidget(parent), d(new Private) { setAttribute(Qt::WA_DeleteOnClose); QHBoxLayout* const hlay = new QHBoxLayout(this); d->previewButtons = new QButtonGroup(this); d->previewButtons->setExclusive(true); hlay->setContentsMargins(QMargins()); hlay->setSpacing(0); d->previewOriginalButton = new QToolButton(this); d->previewButtons->addButton(d->previewOriginalButton, PreviewOriginalImage); hlay->addWidget(d->previewOriginalButton); d->previewOriginalButton->setIcon(QPixmap(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("digikam/data/original.png")))); d->previewOriginalButton->setCheckable(true); d->previewOriginalButton->setWhatsThis(i18n("If this option is enabled, the original image will be shown.")); d->previewOriginalButton->setToolTip(i18n("Preview original image")); d->previewOriginalButton->setObjectName(QLatin1String("preview-original")); d->previewBothButtonVert = new QToolButton(this); d->previewButtons->addButton(d->previewBothButtonVert, PreviewBothImagesVertCont); hlay->addWidget(d->previewBothButtonVert); d->previewBothButtonVert->setIcon(QPixmap(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("digikam/data/bothvert.png")))); d->previewBothButtonVert->setCheckable(true); d->previewBothButtonVert->setWhatsThis(i18n("If this option is enabled, the preview area will " "split vertically. " "A contiguous area of the image will be shown, " "with one half from the original image, " "the other half from the target image.")); d->previewBothButtonVert->setToolTip(i18n("Preview vertical split with contiguous image")); d->previewBothButtonVert->setObjectName(QLatin1String("preview-both-vert")); d->previewBothButtonHorz = new QToolButton(this); d->previewButtons->addButton(d->previewBothButtonHorz, PreviewBothImagesHorzCont); hlay->addWidget(d->previewBothButtonHorz); d->previewBothButtonHorz->setIcon(QPixmap(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("digikam/data/bothhorz.png")))); d->previewBothButtonHorz->setCheckable(true); d->previewBothButtonHorz->setWhatsThis(i18n("If this option is enabled, the preview area will " "split horizontally. " "A contiguous area of the image will be shown, " "with one half from the original image, " "the other half from the target image.")); d->previewBothButtonHorz->setToolTip(i18n("Preview horizontal split with contiguous image")); d->previewBothButtonHorz->setObjectName(QLatin1String("preview--both-horz")); d->previewDuplicateBothButtonVert = new QToolButton(this); d->previewButtons->addButton(d->previewDuplicateBothButtonVert, PreviewBothImagesVert); hlay->addWidget(d->previewDuplicateBothButtonVert); d->previewDuplicateBothButtonVert->setIcon(QPixmap(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("digikam/data/duplicatebothvert.png")))); d->previewDuplicateBothButtonVert->setCheckable(true); d->previewDuplicateBothButtonVert->setWhatsThis(i18n("If this option is enabled, the preview area will " "split vertically. " "The same part of the original and the target image " "will be shown side by side.")); d->previewDuplicateBothButtonVert->setToolTip(i18n("Preview vertical split with same image region")); d->previewDuplicateBothButtonVert->setObjectName(QLatin1String("preview-duplicate-both-vert")); d->previewDupplicateBothButtonHorz = new QToolButton(this); d->previewButtons->addButton(d->previewDupplicateBothButtonHorz, PreviewBothImagesHorz); hlay->addWidget(d->previewDupplicateBothButtonHorz); d->previewDupplicateBothButtonHorz->setIcon(QPixmap(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("digikam/data/duplicatebothhorz.png")))); d->previewDupplicateBothButtonHorz->setCheckable(true); d->previewDupplicateBothButtonHorz->setWhatsThis(i18n("If this option is enabled, the preview area will " "split horizontally. " "The same part of the original and the target image " "will be shown side by side.")); d->previewDupplicateBothButtonHorz->setToolTip(i18n("Preview horizontal split with same image region")); d->previewDupplicateBothButtonHorz->setObjectName(QLatin1String("preview-duplicate-both-horz")); d->previewtargetButton = new QToolButton(this); d->previewButtons->addButton(d->previewtargetButton, PreviewTargetImage); hlay->addWidget(d->previewtargetButton); d->previewtargetButton->setIcon(QPixmap(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("digikam/data/target.png")))); d->previewtargetButton->setCheckable(true); d->previewtargetButton->setWhatsThis(i18n("If this option is enabled, the target image will be shown.")); d->previewtargetButton->setToolTip(i18n("Preview target image")); d->previewtargetButton->setObjectName(QLatin1String("preview-target")); d->previewToggleMouseOverButton = new QToolButton(this); d->previewButtons->addButton(d->previewToggleMouseOverButton, PreviewToggleOnMouseOver); hlay->addWidget(d->previewToggleMouseOverButton); d->previewToggleMouseOverButton->setIcon(QPixmap(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("digikam/data/togglemouseover.png")))); d->previewToggleMouseOverButton->setCheckable(true); d->previewToggleMouseOverButton->setWhatsThis(i18n("If this option is enabled, the original image will " "be shown when the mouse is over image area; otherwise, " "the target image will be shown.")); d->previewToggleMouseOverButton->setToolTip(i18n("Preview on mouse-over")); d->previewToggleMouseOverButton->setObjectName(QLatin1String("preview-toggle-mouse-over")); connect(d->previewButtons, SIGNAL(buttonReleased(int)), this, SLOT(slotButtonReleased(int))); } PreviewToolBar::~PreviewToolBar() { delete d; } void PreviewToolBar::registerMenuActionGroup(EditorWindow* const editor) { d->actionsMenu = new QMenu(i18nc("@action Select image editor preview mode", "Preview Mode"), editor); d->actionsGroup = new QActionGroup(d->actionsMenu); connect(d->actionsGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotActionTriggered(QAction*))); foreach (QAbstractButton* const btn, d->previewButtons->buttons()) { QAction* const ac = new QAction(btn->toolTip(), d->actionsGroup); ac->setData(QVariant(d->previewButtons->id(btn))); ac->setIcon(btn->icon()); ac->setCheckable(true); editor->actionCollection()->addAction(btn->objectName(), ac); d->actionsMenu->addAction(ac); } editor->actionCollection()->addAction(QLatin1String("editorwindow_previewmode"), d->actionsMenu->menuAction()); } void PreviewToolBar::slotActionTriggered(QAction* ac) { int id = ac->data().toInt(); d->previewButtons->button(id)->setChecked(true); emit signalPreviewModeChanged(id); } void PreviewToolBar::slotButtonReleased(int id) { setCheckedAction(id); emit signalPreviewModeChanged(id); } void PreviewToolBar::setCheckedAction(int id) { if (!d->actionsGroup) return; foreach (QAction* const ac, d->actionsGroup->actions()) { if (ac->data().toInt() == id) { ac->setChecked(true); return; } } } void PreviewToolBar::setPreviewModeMask(int mask) { if (mask == NoPreviewMode) { setDisabled(true); if (d->actionsMenu) + { d->actionsMenu->setDisabled(true); + } return; } setDisabled(false); if (d->actionsMenu) + { d->actionsMenu->setDisabled(false); + } d->previewOriginalButton->setEnabled(mask & PreviewOriginalImage); d->previewBothButtonVert->setEnabled(mask & PreviewBothImagesHorz); d->previewBothButtonHorz->setEnabled(mask & PreviewBothImagesVert); d->previewDuplicateBothButtonVert->setEnabled(mask & PreviewBothImagesHorzCont); d->previewDupplicateBothButtonHorz->setEnabled(mask & PreviewBothImagesVertCont); d->previewtargetButton->setEnabled(mask & PreviewTargetImage); d->previewToggleMouseOverButton->setEnabled(mask & PreviewToggleOnMouseOver); if (d->actionsGroup) { foreach (QAction* const ac, d->actionsGroup->actions()) { ac->setEnabled(mask & ac->data().toInt()); } } // When we switch to another mask, check if current mode is valid. + PreviewToolBar::PreviewMode mode = previewMode(); if (d->previewButtons->button(mode)) { if (!d->previewButtons->button(mode)->isEnabled()) { QList btns = d->previewButtons->buttons(); foreach (QAbstractButton* const btn, btns) { if (btn && btn->isEnabled()) { btn->setChecked(true); setCheckedAction(d->previewButtons->id(btn)); + return; } } } } } void PreviewToolBar::setPreviewMode(PreviewMode mode) { if (d->previewButtons->button(mode)) { d->previewButtons->button(mode)->setChecked(true); setCheckedAction((int)mode); } } PreviewToolBar::PreviewMode PreviewToolBar::previewMode() const { if (!isEnabled()) { return PreviewToolBar::NoPreviewMode; } return ((PreviewMode)d->previewButtons->checkedId()); } void PreviewToolBar::readSettings(KConfigGroup& group) { int mode = group.readEntry("PreviewMode", (int)PreviewBothImagesVertCont); mode = qMax((int)PreviewOriginalImage, mode); mode = qMin((int)PreviewToggleOnMouseOver, mode); setPreviewMode((PreviewMode)mode); } void PreviewToolBar::writeSettings(KConfigGroup& group) { group.writeEntry("PreviewMode", (int)previewMode()); } } // namespace Digikam diff --git a/core/utilities/imageeditor/widgets/previewtoolbar.h b/core/utilities/imageeditor/widgets/previewtoolbar.h index 349f8b22fe..0a4e3e3d8e 100644 --- a/core/utilities/imageeditor/widgets/previewtoolbar.h +++ b/core/utilities/imageeditor/widgets/previewtoolbar.h @@ -1,105 +1,105 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2010-01-10 * Description : a tool bar for preview mode * * Copyright (C) 2010-2020 by Gilles Caulier * * 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, 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. * * ============================================================ */ #ifndef DIGIKAM_PREVIEW_TOOL_BAR_H #define DIGIKAM_PREVIEW_TOOL_BAR_H // Qt includes #include // Local includes #include "digikam_export.h" class QAction; class KConfigGroup; namespace Digikam { class EditorWindow; class DIGIKAM_EXPORT PreviewToolBar : public QWidget { Q_OBJECT public: enum PreviewMode { - PreviewOriginalImage = 0x00000001, // Original image only. - PreviewBothImagesHorz = 0x00000002, // Horizontal with original and target duplicated. - PreviewBothImagesVert = 0x00000004, // Vertical with original and target duplicated. - PreviewBothImagesHorzCont = 0x00000008, // Horizontal with original and target in contiguous. - PreviewBothImagesVertCont = 0x00000010, // Vertical with original and target in contiguous. - PreviewTargetImage = 0x00000020, // Target image only. - PreviewToggleOnMouseOver = 0x00000040, // Original image if mouse is over image area, else target image. - NoPreviewMode = 0x00000080, // Target image only without information displayed. + PreviewOriginalImage = 0x00000001, ///< Original image only. + PreviewBothImagesHorz = 0x00000002, ///< Horizontal with original and target duplicated. + PreviewBothImagesVert = 0x00000004, ///< Vertical with original and target duplicated. + PreviewBothImagesHorzCont = 0x00000008, ///< Horizontal with original and target in contiguous. + PreviewBothImagesVertCont = 0x00000010, ///< Vertical with original and target in contiguous. + PreviewTargetImage = 0x00000020, ///< Target image only. + PreviewToggleOnMouseOver = 0x00000040, ///< Original image if mouse is over image area, else target image. + NoPreviewMode = 0x00000080, ///< Target image only without information displayed. AllPreviewModes = PreviewOriginalImage | PreviewBothImagesHorz | PreviewBothImagesVert | PreviewBothImagesHorzCont | PreviewBothImagesVertCont | PreviewTargetImage | PreviewToggleOnMouseOver, UnSplitPreviewModes = PreviewOriginalImage | PreviewTargetImage | PreviewToggleOnMouseOver }; public: explicit PreviewToolBar(QWidget* const parent = nullptr); ~PreviewToolBar(); void setPreviewModeMask(int mask); void setPreviewMode(PreviewMode mode); PreviewMode previewMode() const; void readSettings(KConfigGroup& group); void writeSettings(KConfigGroup& group); void registerMenuActionGroup(EditorWindow* const editor); Q_SIGNALS: void signalPreviewModeChanged(int); private Q_SLOTS: void slotButtonReleased(int); void slotActionTriggered(QAction*); private: void setCheckedAction(int id); private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_PREVIEW_TOOL_BAR_H diff --git a/core/utilities/imageeditor/widgets/rubberitem.cpp b/core/utilities/imageeditor/widgets/rubberitem.cpp index 649d384883..bbb96752d2 100644 --- a/core/utilities/imageeditor/widgets/rubberitem.cpp +++ b/core/utilities/imageeditor/widgets/rubberitem.cpp @@ -1,69 +1,69 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2013-09-13 * Description : rubber item for Canvas * * Copyright (C) 2013-2014 by Yiou Wang * * 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, 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. * * ============================================================ */ #include "rubberitem.h" namespace Digikam { class Q_DECL_HIDDEN RubberItem::Private { public: explicit Private() + : canvas(nullptr) { - canvas = nullptr; } Canvas* canvas; }; RubberItem::RubberItem(ImagePreviewItem* const parent) : RegionFrameItem(parent), d(new Private) { } RubberItem::~RubberItem() { delete d; } void RubberItem::setCanvas(Canvas* const canvas) { d->canvas = canvas; } void RubberItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { RegionFrameItem::mouseReleaseEvent(event); d->canvas->slotSelected(); } void RubberItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event) { RegionFrameItem::mouseMoveEvent(event); d->canvas->slotSelectionMoved(); } } // namespace Digikam diff --git a/core/utilities/imageeditor/widgets/rubberitem.h b/core/utilities/imageeditor/widgets/rubberitem.h index 231cde1ab3..c807af2ba8 100644 --- a/core/utilities/imageeditor/widgets/rubberitem.h +++ b/core/utilities/imageeditor/widgets/rubberitem.h @@ -1,67 +1,67 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2013-09-13 * Description : rubber item for Canvas * * Copyright (C) 2013-2014 by Yiou Wang * * 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, 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. * * ============================================================ */ #ifndef DIGIKAM_RUBBER_ITEM_H #define DIGIKAM_RUBBER_ITEM_H // Qt includes #include // Local includes #include "canvas.h" #include "imagepreviewitem.h" #include "regionframeitem.h" #include "digikam_export.h" class QWidget; namespace Digikam { class DIGIKAM_EXPORT RubberItem : public RegionFrameItem { Q_OBJECT public: explicit RubberItem(ImagePreviewItem* const item); virtual ~RubberItem(); void setCanvas(Canvas* const canvas); protected: void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override; - void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override; private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_RUBBER_ITEM_H