1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2005-02-17
7  * Description : a tool to change image perspective .
8  *
9  * Copyright (C) 2005-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  * Copyright (C) 2006-2012 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
11  *
12  * This program is free software; you can redistribute it
13  * and/or modify it under the terms of the GNU General
14  * Public License as published by the Free Software Foundation;
15  * either version 2, or (at your option)
16  * any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * ============================================================ */
24 
25 #include "perspectivetool.h"
26 
27 // Qt includes
28 
29 #include <QCheckBox>
30 #include <QFrame>
31 #include <QGridLayout>
32 #include <QGroupBox>
33 #include <QLabel>
34 #include <QPushButton>
35 #include <QSpinBox>
36 #include <QVBoxLayout>
37 #include <QApplication>
38 
39 // KDE includes
40 
41 #include <klocalizedstring.h>
42 #include <ksharedconfig.h>
43 #include <kconfiggroup.h>
44 
45 // Local includes
46 
47 #include "dimg.h"
48 #include "editortoolsettings.h"
49 #include "imageiface.h"
50 #include "perspectivewidget.h"
51 #include "dexpanderbox.h"
52 
53 namespace DigikamEditorPerspectiveToolPlugin
54 {
55 
56 class Q_DECL_HIDDEN PerspectiveTool::Private
57 {
58 public:
59 
Private()60     explicit Private()
61       : newWidthLabel           (nullptr),
62         newHeightLabel          (nullptr),
63         topLeftAngleLabel       (nullptr),
64         topRightAngleLabel      (nullptr),
65         bottomLeftAngleLabel    (nullptr),
66         bottomRightAngleLabel   (nullptr),
67         drawWhileMovingCheckBox (nullptr),
68         drawGridCheckBox        (nullptr),
69         inverseTransformation   (nullptr),
70         previewWidget           (nullptr),
71         gboxSettings            (nullptr)
72     {
73     }
74 
75     static const QString configGroupName;
76     static const QString configDrawWhileMovingEntry;
77     static const QString configDrawGridEntry;
78     static const QString configInverseTransformationEntry;
79 
80     QLabel*              newWidthLabel;
81     QLabel*              newHeightLabel;
82     QLabel*              topLeftAngleLabel;
83     QLabel*              topRightAngleLabel;
84     QLabel*              bottomLeftAngleLabel;
85     QLabel*              bottomRightAngleLabel;
86 
87     QCheckBox*           drawWhileMovingCheckBox;
88     QCheckBox*           drawGridCheckBox;
89     QCheckBox*           inverseTransformation;
90 
91     PerspectiveWidget*   previewWidget;
92     EditorToolSettings*  gboxSettings;
93 };
94 
95 const QString PerspectiveTool::Private::configGroupName(QLatin1String("perspective Tool"));
96 const QString PerspectiveTool::Private::configDrawWhileMovingEntry(QLatin1String("Draw While Moving"));
97 const QString PerspectiveTool::Private::configDrawGridEntry(QLatin1String("Draw Grid"));
98 const QString PerspectiveTool::Private::configInverseTransformationEntry(QLatin1String("Inverse Transformation"));
99 
100 // --------------------------------------------------------
101 
PerspectiveTool(QObject * const parent)102 PerspectiveTool::PerspectiveTool(QObject* const parent)
103     : EditorTool(parent),
104       d         (new Private)
105 {
106     setObjectName(QLatin1String("perspective"));
107 
108     // -------------------------------------------------------------
109 
110     QFrame* const frame  = new QFrame(nullptr);
111     frame->setFrameStyle(QFrame::Panel|QFrame::Sunken);
112     QVBoxLayout* const l = new QVBoxLayout(frame);
113     d->previewWidget     = new PerspectiveWidget(525, 350, frame);
114     l->addWidget(d->previewWidget);
115     d->previewWidget->setWhatsThis(i18n("This is the perspective transformation operation preview. "
116                                         "You can use the mouse for dragging the corner to adjust the "
117                                         "perspective transformation area."));
118     setToolView(frame);
119 
120     // -------------------------------------------------------------
121 
122     QString temp;
123     ImageIface iface;
124 
125     d->gboxSettings      = new EditorToolSettings(nullptr);
126     d->gboxSettings->setTools(EditorToolSettings::ColorGuide);
127 
128     // -------------------------------------------------------------
129 
130     QLabel* const label1 = new QLabel(i18n("New width:"));
131     d->newWidthLabel     = new QLabel(temp.setNum( iface.originalSize().width()) + i18n(" px"));
132     d->newWidthLabel->setAlignment( Qt::AlignBottom | Qt::AlignRight );
133 
134     QLabel* const label2 = new QLabel(i18n("New height:"));
135     d->newHeightLabel    = new QLabel(temp.setNum( iface.originalSize().height()) + i18n(" px"));
136     d->newHeightLabel->setAlignment( Qt::AlignBottom | Qt::AlignRight );
137 
138     // -------------------------------------------------------------
139 
140     DLineWidget* const line  = new DLineWidget (Qt::Horizontal);
141     QLabel* const angleLabel = new QLabel(i18n("Angles (in degrees):"));
142     QLabel* const label3     = new QLabel(i18n("  Top left:"));
143     d->topLeftAngleLabel     = new QLabel;
144     QLabel* const label4     = new QLabel(i18n("  Top right:"));
145     d->topRightAngleLabel    = new QLabel;
146     QLabel* const label5     = new QLabel(i18n("  Bottom left:"));
147     d->bottomLeftAngleLabel  = new QLabel;
148     QLabel* const label6     = new QLabel(i18n("  Bottom right:"));
149     d->bottomRightAngleLabel = new QLabel;
150 
151     // -------------------------------------------------------------
152 
153     DLineWidget* const line2   = new DLineWidget (Qt::Horizontal);
154     d->drawWhileMovingCheckBox = new QCheckBox(i18n("Draw preview while moving"));
155     d->drawGridCheckBox        = new QCheckBox(i18n("Draw grid"));
156     d->inverseTransformation   = new QCheckBox(i18n("Inverse transformation"));
157 
158     // -------------------------------------------------------------
159 
160     const int spacing = d->gboxSettings->spacingHint();
161 
162     QGridLayout* const grid = new QGridLayout;
163     grid->addWidget(label1,                       0, 0, 1, 1);
164     grid->addWidget(d->newWidthLabel,             0, 1, 1, 2);
165     grid->addWidget(label2,                       1, 0, 1, 1);
166     grid->addWidget(d->newHeightLabel,            1, 1, 1, 2);
167     grid->addWidget(line,                         2, 0, 1, 3);
168     grid->addWidget(angleLabel,                   3, 0, 1, 3);
169     grid->addWidget(label3,                       4, 0, 1, 1);
170     grid->addWidget(d->topLeftAngleLabel,         4, 1, 1, 2);
171     grid->addWidget(label4,                       5, 0, 1, 1);
172     grid->addWidget(d->topRightAngleLabel,        5, 1, 1, 2);
173     grid->addWidget(label5,                       6, 0, 1, 1);
174     grid->addWidget(d->bottomLeftAngleLabel,      6, 1, 1, 2);
175     grid->addWidget(label6,                       7, 0, 1, 1);
176     grid->addWidget(d->bottomRightAngleLabel,     7, 1, 1, 2);
177     grid->addWidget(line2,                        8, 0, 1, 3);
178     grid->addWidget(d->drawWhileMovingCheckBox,   9, 0, 1, 3);
179     grid->addWidget(d->drawGridCheckBox,         10, 0, 1, 3);
180     grid->addWidget(d->inverseTransformation,    11, 0, 1, 3);
181     grid->setColumnStretch(1, 10);
182     grid->setRowStretch(12, 10);
183     grid->setContentsMargins(spacing, spacing, spacing, spacing);
184     grid->setSpacing(spacing);
185     d->gboxSettings->plainPage()->setLayout(grid);
186 
187     // -------------------------------------------------------------
188 
189     setToolSettings(d->gboxSettings);
190 
191     // -------------------------------------------------------------
192 
193     connect(d->previewWidget, SIGNAL(signalPerspectiveChanged(QRect,float,float,float,float,bool)),
194             this, SLOT(slotUpdateInfo(QRect,float,float,float,float,bool)));
195 
196     connect(d->drawWhileMovingCheckBox, SIGNAL(toggled(bool)),
197             d->previewWidget, SLOT(slotToggleDrawWhileMoving(bool)));
198 
199     connect(d->drawGridCheckBox, SIGNAL(toggled(bool)),
200             d->previewWidget, SLOT(slotToggleDrawGrid(bool)));
201 
202     connect(d->inverseTransformation, SIGNAL(toggled(bool)),
203             this, SLOT(slotInverseTransformationChanged(bool)));
204 
205     connect(d->gboxSettings, SIGNAL(signalColorGuideChanged()),
206             this, SLOT(slotColorGuideChanged()));
207 }
208 
~PerspectiveTool()209 PerspectiveTool::~PerspectiveTool()
210 {
211     delete d;
212 }
213 
slotColorGuideChanged()214 void PerspectiveTool::slotColorGuideChanged()
215 {
216     d->previewWidget->slotChangeGuideColor(d->gboxSettings->guideColor());
217     d->previewWidget->slotChangeGuideSize(d->gboxSettings->guideSize());
218 }
219 
readSettings()220 void PerspectiveTool::readSettings()
221 {
222     QColor defaultGuideColor(Qt::red);
223     KSharedConfig::Ptr config = KSharedConfig::openConfig();
224     KConfigGroup group        = config->group(d->configGroupName);
225 
226     d->drawWhileMovingCheckBox->setChecked(group.readEntry( d->configDrawWhileMovingEntry,       true));
227     d->drawGridCheckBox->setChecked(group.readEntry(        d->configDrawGridEntry,              false));
228     d->inverseTransformation->setChecked(group.readEntry(   d->configInverseTransformationEntry, false));
229 
230     d->previewWidget->slotToggleDrawWhileMoving(d->drawWhileMovingCheckBox->isChecked());
231     d->previewWidget->slotToggleDrawGrid(d->drawGridCheckBox->isChecked());
232 }
233 
writeSettings()234 void PerspectiveTool::writeSettings()
235 {
236     KSharedConfig::Ptr config = KSharedConfig::openConfig();
237     KConfigGroup group        = config->group(d->configGroupName);
238 
239     group.writeEntry(d->configDrawWhileMovingEntry,       d->drawWhileMovingCheckBox->isChecked());
240     group.writeEntry(d->configDrawGridEntry,              d->drawGridCheckBox->isChecked());
241     group.writeEntry(d->configInverseTransformationEntry, d->inverseTransformation->isChecked());
242     config->sync();
243 }
244 
slotResetSettings()245 void PerspectiveTool::slotResetSettings()
246 {
247     d->previewWidget->reset();
248 }
249 
finalRendering()250 void PerspectiveTool::finalRendering()
251 {
252     qApp->setOverrideCursor(Qt::WaitCursor);
253     d->previewWidget->applyPerspectiveAdjustment();
254     qApp->restoreOverrideCursor();
255 }
256 
slotUpdateInfo(const QRect & newSize,float topLeftAngle,float topRightAngle,float bottomLeftAngle,float bottomRightAngle,bool valid)257 void PerspectiveTool::slotUpdateInfo(const QRect& newSize, float topLeftAngle, float topRightAngle,
258                                      float bottomLeftAngle, float bottomRightAngle, bool valid)
259 {
260     QString temp;
261     d->newWidthLabel->setText(temp.setNum(newSize.width()) + i18n(" px"));
262     d->newHeightLabel->setText(temp.setNum(newSize.height()) + i18n(" px"));
263 
264     d->topLeftAngleLabel->setText(temp.setNum(topLeftAngle, 'f', 1));
265     d->topRightAngleLabel->setText(temp.setNum(topRightAngle, 'f', 1));
266     d->bottomLeftAngleLabel->setText(temp.setNum(bottomLeftAngle, 'f', 1));
267     d->bottomRightAngleLabel->setText(temp.setNum(bottomRightAngle, 'f', 1));
268 
269     d->gboxSettings->button(EditorToolSettings::Ok)->setEnabled(valid);
270 }
271 
slotInverseTransformationChanged(bool b)272 void PerspectiveTool::slotInverseTransformationChanged(bool b)
273 {
274     d->drawWhileMovingCheckBox->setEnabled(!b);
275     d->drawGridCheckBox->setEnabled(!b);
276     d->previewWidget->slotInverseTransformationChanged(b);
277 }
278 
setBackgroundColor(const QColor & bg)279 void PerspectiveTool::setBackgroundColor(const QColor& bg)
280 {
281     d->previewWidget->setBackgroundColor(bg);
282 }
283 
284 } // namespace DigikamEditorPerspectiveToolPlugin
285