File indexing completed on 2024-05-12 04:19:47

0001 // vim: set tabstop=4 shiftwidth=4 expandtab:
0002 /*
0003 Gwenview: an image viewer
0004 Copyright 2007 Aurélien Gâteau <agateau@kde.org>
0005 
0006 This program is free software; you can redistribute it and/or
0007 modify it under the terms of the GNU General Public License
0008 as published by the Free Software Foundation; either version 2
0009 of the License, or (at your option) any later version.
0010 
0011 This program is distributed in the hope that it will be useful,
0012 but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 GNU General Public License for more details.
0015 
0016 You should have received a copy of the GNU General Public License
0017 along with this program; if not, write to the Free Software
0018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0019 
0020 */
0021 // Self
0022 #include "redeyereductiontool.h"
0023 
0024 // Qt
0025 #include <QDialogButtonBox>
0026 #include <QGraphicsSceneMouseEvent>
0027 #include <QPainter>
0028 #include <QPushButton>
0029 #include <QRect>
0030 
0031 // KF
0032 
0033 // Local
0034 #include "gwenview_lib_debug.h"
0035 #include "gwenviewconfig.h"
0036 #include "redeyereductionimageoperation.h"
0037 #include "ui_redeyereductionwidget.h"
0038 #include <lib/documentview/rasterimageview.h>
0039 
0040 namespace Gwenview
0041 {
0042 struct RedEyeReductionWidget : public QWidget, public Ui_RedEyeReductionWidget {
0043     RedEyeReductionWidget()
0044     {
0045         setupUi(this);
0046         QPushButton *okButton = mainDialogButtonBox->button(QDialogButtonBox::Ok);
0047         okButton->setIcon(QIcon::fromTheme(QStringLiteral("redeyes")));
0048         okButton->setText(i18n("Reduce Red Eye"));
0049     }
0050 
0051     void showNotSetPage()
0052     {
0053         // Prevent Close button from turning blue upon accepting
0054         helpTextLabel->setFocus();
0055 
0056         stackedWidget->setCurrentWidget(notSetPage);
0057     }
0058 
0059     void showMainPage()
0060     {
0061         stackedWidget->setCurrentWidget(mainPage);
0062     }
0063 };
0064 
0065 struct RedEyeReductionToolPrivate {
0066     RedEyeReductionTool *q = nullptr;
0067     RedEyeReductionTool::Status mStatus;
0068     QPointF mCenter;
0069     int mDiameter;
0070     RedEyeReductionWidget *mToolWidget = nullptr;
0071 
0072     void setupToolWidget()
0073     {
0074         mToolWidget = new RedEyeReductionWidget;
0075         mToolWidget->showNotSetPage();
0076         QObject::connect(mToolWidget->diameterSpinBox, SIGNAL(valueChanged(int)), q, SLOT(setDiameter(int)));
0077         QObject::connect(mToolWidget->mainDialogButtonBox, &QDialogButtonBox::accepted, q, &RedEyeReductionTool::slotApplyClicked);
0078         QObject::connect(mToolWidget->mainDialogButtonBox, &QDialogButtonBox::rejected, q, &RedEyeReductionTool::done);
0079         QObject::connect(mToolWidget->helpDialogButtonBox, &QDialogButtonBox::rejected, q, &RedEyeReductionTool::done);
0080     }
0081 
0082     QRectF rectF() const
0083     {
0084         if (mStatus == RedEyeReductionTool::NotSet) {
0085             return QRectF();
0086         }
0087         return QRectF(mCenter.x() - mDiameter / 2, mCenter.y() - mDiameter / 2, mDiameter, mDiameter);
0088     }
0089 };
0090 
0091 RedEyeReductionTool::RedEyeReductionTool(RasterImageView *view)
0092     : AbstractRasterImageViewTool(view)
0093     , d(new RedEyeReductionToolPrivate)
0094 {
0095     d->q = this;
0096     d->mDiameter = GwenviewConfig::redEyeReductionDiameter();
0097     d->mStatus = NotSet;
0098     d->setupToolWidget();
0099 
0100     view->document()->startLoadingFullImage();
0101 }
0102 
0103 RedEyeReductionTool::~RedEyeReductionTool()
0104 {
0105     GwenviewConfig::setRedEyeReductionDiameter(d->mDiameter);
0106     delete d->mToolWidget;
0107     delete d;
0108 }
0109 
0110 void RedEyeReductionTool::paint(QPainter *painter)
0111 {
0112     if (d->mStatus == NotSet) {
0113         return;
0114     }
0115     const QRectF docRectF = d->rectF();
0116     imageView()->document()->waitUntilLoaded();
0117 
0118     const QRect docRect = docRectF.toAlignedRect();
0119     QImage img = imageView()->document()->image().copy(docRect);
0120     const QRectF imgRectF(docRectF.left() - docRect.left(), docRectF.top() - docRect.top(), docRectF.width(), docRectF.height());
0121     RedEyeReductionImageOperation::apply(&img, imgRectF);
0122 
0123     const QRectF viewRectF = imageView()->mapToView(docRectF);
0124     painter->drawImage(viewRectF, img, imgRectF);
0125 }
0126 
0127 void RedEyeReductionTool::mousePressEvent(QGraphicsSceneMouseEvent *event)
0128 {
0129     if (event->buttons() != Qt::LeftButton || event->modifiers() & Qt::ControlModifier) {
0130         event->ignore();
0131         return;
0132     }
0133     event->accept();
0134     if (d->mStatus == NotSet) {
0135         d->mToolWidget->diameterSpinBox->setValue(d->mDiameter);
0136         d->mToolWidget->showMainPage();
0137         d->mStatus = Adjusting;
0138     }
0139     d->mCenter = imageView()->mapToImage(event->pos());
0140     imageView()->update();
0141 }
0142 
0143 void RedEyeReductionTool::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
0144 {
0145     event->accept();
0146     if (event->buttons() == Qt::NoButton) {
0147         return;
0148     }
0149     d->mCenter = imageView()->mapToImage(event->pos());
0150     imageView()->update();
0151 }
0152 
0153 void RedEyeReductionTool::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
0154 {
0155     // Just prevent the event from reaching the image view
0156     event->accept();
0157 }
0158 
0159 void RedEyeReductionTool::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
0160 {
0161     if (event->buttons() != Qt::LeftButton) {
0162         event->ignore();
0163         return;
0164     }
0165     event->accept();
0166     Q_EMIT d->mToolWidget->mainDialogButtonBox->accepted();
0167 }
0168 
0169 void RedEyeReductionTool::keyPressEvent(QKeyEvent *event)
0170 {
0171     QDialogButtonBox *buttons;
0172     if (d->mStatus == Adjusting) {
0173         buttons = d->mToolWidget->mainDialogButtonBox;
0174     } else {
0175         buttons = d->mToolWidget->helpDialogButtonBox;
0176     }
0177 
0178     switch (event->key()) {
0179     case Qt::Key_Escape:
0180         event->accept();
0181         Q_EMIT buttons->rejected();
0182         break;
0183     case Qt::Key_Return:
0184     case Qt::Key_Enter: {
0185         event->accept();
0186         auto focusButton = static_cast<QPushButton *>(buttons->focusWidget());
0187         if (focusButton && buttons->buttonRole(focusButton) == QDialogButtonBox::RejectRole) {
0188             Q_EMIT buttons->rejected();
0189         } else {
0190             Q_EMIT buttons->accepted();
0191         }
0192         break;
0193     }
0194     default:
0195         break;
0196     }
0197 }
0198 
0199 void RedEyeReductionTool::toolActivated()
0200 {
0201     imageView()->setCursor(Qt::CrossCursor);
0202 }
0203 
0204 void RedEyeReductionTool::slotApplyClicked()
0205 {
0206     QRectF docRectF = d->rectF();
0207     if (!docRectF.isValid()) {
0208         qCWarning(GWENVIEW_LIB_LOG) << "invalid rect";
0209         return;
0210     }
0211     auto op = new RedEyeReductionImageOperation(docRectF);
0212     Q_EMIT imageOperationRequested(op);
0213 
0214     d->mStatus = NotSet;
0215     d->mToolWidget->showNotSetPage();
0216 }
0217 
0218 void RedEyeReductionTool::setDiameter(int value)
0219 {
0220     d->mDiameter = value;
0221     imageView()->update();
0222 }
0223 
0224 QWidget *RedEyeReductionTool::widget() const
0225 {
0226     return d->mToolWidget;
0227 }
0228 
0229 } // namespace
0230 
0231 #include "moc_redeyereductiontool.cpp"