File indexing completed on 2025-01-19 03:51:13

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2005-02-17
0007  * Description : a tool to change image perspective .
0008  *
0009  * SPDX-FileCopyrightText: 2005-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2006-2012 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "perspectivetool.h"
0017 
0018 // Qt includes
0019 
0020 #include <QCheckBox>
0021 #include <QFrame>
0022 #include <QGridLayout>
0023 #include <QGroupBox>
0024 #include <QLabel>
0025 #include <QPushButton>
0026 #include <QSpinBox>
0027 #include <QVBoxLayout>
0028 #include <QApplication>
0029 
0030 // KDE includes
0031 
0032 #include <klocalizedstring.h>
0033 #include <ksharedconfig.h>
0034 #include <kconfiggroup.h>
0035 
0036 // Local includes
0037 
0038 #include "dimg.h"
0039 #include "editortoolsettings.h"
0040 #include "imageiface.h"
0041 #include "perspectivewidget.h"
0042 #include "dexpanderbox.h"
0043 
0044 namespace DigikamEditorPerspectiveToolPlugin
0045 {
0046 
0047 class Q_DECL_HIDDEN PerspectiveTool::Private
0048 {
0049 public:
0050 
0051     explicit Private()
0052       : newWidthLabel           (nullptr),
0053         newHeightLabel          (nullptr),
0054         topLeftAngleLabel       (nullptr),
0055         topRightAngleLabel      (nullptr),
0056         bottomLeftAngleLabel    (nullptr),
0057         bottomRightAngleLabel   (nullptr),
0058         drawWhileMovingCheckBox (nullptr),
0059         drawGridCheckBox        (nullptr),
0060         inverseTransformation   (nullptr),
0061         previewWidget           (nullptr),
0062         gboxSettings            (nullptr)
0063     {
0064     }
0065 
0066     static const QString configGroupName;
0067     static const QString configDrawWhileMovingEntry;
0068     static const QString configDrawGridEntry;
0069     static const QString configInverseTransformationEntry;
0070 
0071     QLabel*              newWidthLabel;
0072     QLabel*              newHeightLabel;
0073     QLabel*              topLeftAngleLabel;
0074     QLabel*              topRightAngleLabel;
0075     QLabel*              bottomLeftAngleLabel;
0076     QLabel*              bottomRightAngleLabel;
0077 
0078     QCheckBox*           drawWhileMovingCheckBox;
0079     QCheckBox*           drawGridCheckBox;
0080     QCheckBox*           inverseTransformation;
0081 
0082     PerspectiveWidget*   previewWidget;
0083     EditorToolSettings*  gboxSettings;
0084 };
0085 
0086 const QString PerspectiveTool::Private::configGroupName(QLatin1String("perspective Tool"));
0087 const QString PerspectiveTool::Private::configDrawWhileMovingEntry(QLatin1String("Draw While Moving"));
0088 const QString PerspectiveTool::Private::configDrawGridEntry(QLatin1String("Draw Grid"));
0089 const QString PerspectiveTool::Private::configInverseTransformationEntry(QLatin1String("Inverse Transformation"));
0090 
0091 // --------------------------------------------------------
0092 
0093 PerspectiveTool::PerspectiveTool(QObject* const parent)
0094     : EditorTool(parent),
0095       d         (new Private)
0096 {
0097     setObjectName(QLatin1String("perspective"));
0098 
0099     // -------------------------------------------------------------
0100 
0101     QFrame* const frame  = new QFrame(nullptr);
0102     frame->setFrameStyle(QFrame::Panel|QFrame::Sunken);
0103     QVBoxLayout* const l = new QVBoxLayout(frame);
0104     d->previewWidget     = new PerspectiveWidget(525, 350, frame);
0105     l->addWidget(d->previewWidget);
0106     d->previewWidget->setWhatsThis(i18n("This is the perspective transformation operation preview. "
0107                                         "You can use the mouse for dragging the corner to adjust the "
0108                                         "perspective transformation area."));
0109     setToolView(frame);
0110 
0111     // -------------------------------------------------------------
0112 
0113     QString temp;
0114     ImageIface iface;
0115 
0116     d->gboxSettings      = new EditorToolSettings(nullptr);
0117     d->gboxSettings->setTools(EditorToolSettings::ColorGuide);
0118 
0119     // -------------------------------------------------------------
0120 
0121     QLabel* const label1 = new QLabel(i18n("New width:"));
0122     d->newWidthLabel     = new QLabel(temp.setNum( iface.originalSize().width()) + i18n(" px"));
0123     d->newWidthLabel->setAlignment( Qt::AlignBottom | Qt::AlignRight );
0124 
0125     QLabel* const label2 = new QLabel(i18n("New height:"));
0126     d->newHeightLabel    = new QLabel(temp.setNum( iface.originalSize().height()) + i18n(" px"));
0127     d->newHeightLabel->setAlignment( Qt::AlignBottom | Qt::AlignRight );
0128 
0129     // -------------------------------------------------------------
0130 
0131     DLineWidget* const line  = new DLineWidget (Qt::Horizontal);
0132     QLabel* const angleLabel = new QLabel(i18n("Angles (in degrees):"));
0133     QLabel* const label3     = new QLabel(i18n("  Top left:"));
0134     d->topLeftAngleLabel     = new QLabel;
0135     QLabel* const label4     = new QLabel(i18n("  Top right:"));
0136     d->topRightAngleLabel    = new QLabel;
0137     QLabel* const label5     = new QLabel(i18n("  Bottom left:"));
0138     d->bottomLeftAngleLabel  = new QLabel;
0139     QLabel* const label6     = new QLabel(i18n("  Bottom right:"));
0140     d->bottomRightAngleLabel = new QLabel;
0141 
0142     // -------------------------------------------------------------
0143 
0144     DLineWidget* const line2   = new DLineWidget (Qt::Horizontal);
0145     d->drawWhileMovingCheckBox = new QCheckBox(i18n("Draw preview while moving"));
0146     d->drawGridCheckBox        = new QCheckBox(i18n("Draw grid"));
0147     d->inverseTransformation   = new QCheckBox(i18n("Inverse transformation"));
0148 
0149     // -------------------------------------------------------------
0150 
0151     const int spacing = d->gboxSettings->spacingHint();
0152 
0153     QGridLayout* const grid = new QGridLayout;
0154     grid->addWidget(label1,                       0, 0, 1, 1);
0155     grid->addWidget(d->newWidthLabel,             0, 1, 1, 2);
0156     grid->addWidget(label2,                       1, 0, 1, 1);
0157     grid->addWidget(d->newHeightLabel,            1, 1, 1, 2);
0158     grid->addWidget(line,                         2, 0, 1, 3);
0159     grid->addWidget(angleLabel,                   3, 0, 1, 3);
0160     grid->addWidget(label3,                       4, 0, 1, 1);
0161     grid->addWidget(d->topLeftAngleLabel,         4, 1, 1, 2);
0162     grid->addWidget(label4,                       5, 0, 1, 1);
0163     grid->addWidget(d->topRightAngleLabel,        5, 1, 1, 2);
0164     grid->addWidget(label5,                       6, 0, 1, 1);
0165     grid->addWidget(d->bottomLeftAngleLabel,      6, 1, 1, 2);
0166     grid->addWidget(label6,                       7, 0, 1, 1);
0167     grid->addWidget(d->bottomRightAngleLabel,     7, 1, 1, 2);
0168     grid->addWidget(line2,                        8, 0, 1, 3);
0169     grid->addWidget(d->drawWhileMovingCheckBox,   9, 0, 1, 3);
0170     grid->addWidget(d->drawGridCheckBox,         10, 0, 1, 3);
0171     grid->addWidget(d->inverseTransformation,    11, 0, 1, 3);
0172     grid->setColumnStretch(1, 10);
0173     grid->setRowStretch(12, 10);
0174     grid->setContentsMargins(spacing, spacing, spacing, spacing);
0175     grid->setSpacing(spacing);
0176     d->gboxSettings->plainPage()->setLayout(grid);
0177 
0178     // -------------------------------------------------------------
0179 
0180     setToolSettings(d->gboxSettings);
0181 
0182     // -------------------------------------------------------------
0183 
0184     connect(d->previewWidget, SIGNAL(signalPerspectiveChanged(QRect,float,float,float,float,bool)),
0185             this, SLOT(slotUpdateInfo(QRect,float,float,float,float,bool)));
0186 
0187     connect(d->drawWhileMovingCheckBox, SIGNAL(toggled(bool)),
0188             d->previewWidget, SLOT(slotToggleDrawWhileMoving(bool)));
0189 
0190     connect(d->drawGridCheckBox, SIGNAL(toggled(bool)),
0191             d->previewWidget, SLOT(slotToggleDrawGrid(bool)));
0192 
0193     connect(d->inverseTransformation, SIGNAL(toggled(bool)),
0194             this, SLOT(slotInverseTransformationChanged(bool)));
0195 
0196     connect(d->gboxSettings, SIGNAL(signalColorGuideChanged()),
0197             this, SLOT(slotColorGuideChanged()));
0198 }
0199 
0200 PerspectiveTool::~PerspectiveTool()
0201 {
0202     delete d;
0203 }
0204 
0205 void PerspectiveTool::slotColorGuideChanged()
0206 {
0207     d->previewWidget->slotChangeGuideColor(d->gboxSettings->guideColor());
0208     d->previewWidget->slotChangeGuideSize(d->gboxSettings->guideSize());
0209 }
0210 
0211 void PerspectiveTool::readSettings()
0212 {
0213     QColor defaultGuideColor(Qt::red);
0214     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0215     KConfigGroup group        = config->group(d->configGroupName);
0216 
0217     d->drawWhileMovingCheckBox->setChecked(group.readEntry( d->configDrawWhileMovingEntry,       true));
0218     d->drawGridCheckBox->setChecked(group.readEntry(        d->configDrawGridEntry,              false));
0219     d->inverseTransformation->setChecked(group.readEntry(   d->configInverseTransformationEntry, false));
0220 
0221     d->previewWidget->slotToggleDrawWhileMoving(d->drawWhileMovingCheckBox->isChecked());
0222     d->previewWidget->slotToggleDrawGrid(d->drawGridCheckBox->isChecked());
0223 }
0224 
0225 void PerspectiveTool::writeSettings()
0226 {
0227     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0228     KConfigGroup group        = config->group(d->configGroupName);
0229 
0230     group.writeEntry(d->configDrawWhileMovingEntry,       d->drawWhileMovingCheckBox->isChecked());
0231     group.writeEntry(d->configDrawGridEntry,              d->drawGridCheckBox->isChecked());
0232     group.writeEntry(d->configInverseTransformationEntry, d->inverseTransformation->isChecked());
0233     config->sync();
0234 }
0235 
0236 void PerspectiveTool::slotResetSettings()
0237 {
0238     d->previewWidget->reset();
0239 }
0240 
0241 void PerspectiveTool::finalRendering()
0242 {
0243     qApp->setOverrideCursor(Qt::WaitCursor);
0244     d->previewWidget->applyPerspectiveAdjustment();
0245     qApp->restoreOverrideCursor();
0246 }
0247 
0248 void PerspectiveTool::slotUpdateInfo(const QRect& newSize, float topLeftAngle, float topRightAngle,
0249                                      float bottomLeftAngle, float bottomRightAngle, bool valid)
0250 {
0251     QString temp;
0252     d->newWidthLabel->setText(temp.setNum(newSize.width()) + i18n(" px"));
0253     d->newHeightLabel->setText(temp.setNum(newSize.height()) + i18n(" px"));
0254 
0255     d->topLeftAngleLabel->setText(temp.setNum(topLeftAngle, 'f', 1));
0256     d->topRightAngleLabel->setText(temp.setNum(topRightAngle, 'f', 1));
0257     d->bottomLeftAngleLabel->setText(temp.setNum(bottomLeftAngle, 'f', 1));
0258     d->bottomRightAngleLabel->setText(temp.setNum(bottomRightAngle, 'f', 1));
0259 
0260     d->gboxSettings->button(EditorToolSettings::Ok)->setEnabled(valid);
0261 }
0262 
0263 void PerspectiveTool::slotInverseTransformationChanged(bool b)
0264 {
0265     d->drawWhileMovingCheckBox->setEnabled(!b);
0266     d->drawGridCheckBox->setEnabled(!b);
0267     d->previewWidget->slotInverseTransformationChanged(b);
0268 }
0269 
0270 void PerspectiveTool::setBackgroundColor(const QColor& bg)
0271 {
0272     d->previewWidget->setBackgroundColor(bg);
0273 }
0274 
0275 } // namespace DigikamEditorPerspectiveToolPlugin
0276 
0277 #include "moc_perspectivetool.cpp"