1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2004-09-30
7  * Description : a tool to add rain drop over an image
8  *
9  * Copyright (C) 2004-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 "raindroptool.h"
26 
27 // Qt includes
28 
29 #include <QFrame>
30 #include <QGridLayout>
31 #include <QImage>
32 #include <QLabel>
33 #include <QIcon>
34 
35 // KDE includes
36 
37 #include <ksharedconfig.h>
38 #include <kconfiggroup.h>
39 #include <klocalizedstring.h>
40 
41 // Local includes
42 
43 #include "dnuminput.h"
44 #include "editortoolsettings.h"
45 #include "imageiface.h"
46 #include "imageguidewidget.h"
47 #include "raindropfilter.h"
48 
49 namespace DigikamEditorRainDropToolPlugin
50 {
51 
52 class Q_DECL_HIDDEN RainDropTool::Private
53 {
54 public:
55 
Private()56     explicit Private()
57       : dropInput       (nullptr),
58         amountInput     (nullptr),
59         coeffInput      (nullptr),
60         previewWidget   (nullptr),
61         gboxSettings    (nullptr)
62     {
63     }
64 
65     static const QString configGroupName;
66     static const QString configDropAdjustmentEntry;
67     static const QString configAmountAdjustmentEntry;
68     static const QString configCoeffAdjustmentEntry;
69 
70     DIntNumInput*        dropInput;
71     DIntNumInput*        amountInput;
72     DIntNumInput*        coeffInput;
73 
74     ImageGuideWidget*    previewWidget;
75     EditorToolSettings*  gboxSettings;
76 };
77 
78 const QString RainDropTool::Private::configGroupName(QLatin1String("raindrops Tool"));
79 const QString RainDropTool::Private::configDropAdjustmentEntry(QLatin1String("DropAdjustment"));
80 const QString RainDropTool::Private::configAmountAdjustmentEntry(QLatin1String("AmountAdjustment"));
81 const QString RainDropTool::Private::configCoeffAdjustmentEntry(QLatin1String("CoeffAdjustment"));
82 
83 // --------------------------------------------------------
84 
RainDropTool(QObject * const parent)85 RainDropTool::RainDropTool(QObject* const parent)
86     : EditorToolThreaded(parent),
87       d                 (new Private)
88 {
89     setObjectName(QLatin1String("raindrops"));
90 
91     d->previewWidget = new ImageGuideWidget(nullptr, false, ImageGuideWidget::HVGuideMode);
92     d->previewWidget->setWhatsThis(i18n("This is the preview of the Raindrop effect."
93                                         "<p>Note: if you have previously selected an area in the editor, "
94                                         "this will be unaffected by the filter. You can use this method to "
95                                         "disable the Raindrops effect on a human face, for example.</p>"));
96 
97     setToolView(d->previewWidget);
98     setPreviewModeMask(PreviewToolBar::AllPreviewModes);
99 
100     // -------------------------------------------------------------
101 
102     d->gboxSettings = new EditorToolSettings(nullptr);
103     d->gboxSettings->setButtons(EditorToolSettings::Default|
104                                 EditorToolSettings::Ok|
105                                 EditorToolSettings::Try|
106                                 EditorToolSettings::Cancel);
107 
108 
109     // -------------------------------------------------------------
110 
111     QLabel* label1 = new QLabel(i18n("Drop size:"));
112     d->dropInput   = new DIntNumInput;
113     d->dropInput->setRange(0, 200, 1);
114     d->dropInput->setDefaultValue(80);
115     d->dropInput->setWhatsThis( i18n("Set here the raindrops' size."));
116 
117     // -------------------------------------------------------------
118 
119     QLabel* label2 = new QLabel(i18n("Number:"));
120     d->amountInput = new DIntNumInput;
121     d->amountInput->setRange(1, 500, 1);
122     d->amountInput->setDefaultValue(150);
123     d->amountInput->setWhatsThis( i18n("This value controls the maximum number of raindrops."));
124 
125     // -------------------------------------------------------------
126 
127     QLabel* label3 = new QLabel(i18n("Fish eyes:"));
128     d->coeffInput  = new DIntNumInput;
129     d->coeffInput->setRange(1, 100, 1);
130     d->coeffInput->setDefaultValue(30);
131     d->coeffInput->setWhatsThis( i18n("This value is the fish-eye-effect optical "
132                                       "distortion coefficient."));
133 
134     // -------------------------------------------------------------
135 
136     const int spacing = d->gboxSettings->spacingHint();
137 
138     QGridLayout* mainLayout = new QGridLayout;
139     mainLayout->addWidget(label1,         0, 0, 1, 3);
140     mainLayout->addWidget(d->dropInput,   1, 0, 1, 3);
141     mainLayout->addWidget(label2,         2, 0, 1, 3);
142     mainLayout->addWidget(d->amountInput, 3, 0, 1, 3);
143     mainLayout->addWidget(label3,         4, 0, 1, 3);
144     mainLayout->addWidget(d->coeffInput,  5, 0, 1, 3);
145     mainLayout->setRowStretch(6, 10);
146     mainLayout->setContentsMargins(spacing, spacing, spacing, spacing);
147     mainLayout->setSpacing(spacing);
148     d->gboxSettings->plainPage()->setLayout(mainLayout);
149 
150     // -------------------------------------------------------------
151 
152     setToolSettings(d->gboxSettings);
153 }
154 
~RainDropTool()155 RainDropTool::~RainDropTool()
156 {
157     delete d;
158 }
159 
readSettings()160 void RainDropTool::readSettings()
161 {
162     KSharedConfig::Ptr config = KSharedConfig::openConfig();
163     KConfigGroup group        = config->group(d->configGroupName);
164 
165     blockWidgetSignals(true);
166 
167     d->dropInput->setValue(group.readEntry(d->configDropAdjustmentEntry,     d->dropInput->defaultValue()));
168     d->amountInput->setValue(group.readEntry(d->configAmountAdjustmentEntry, d->amountInput->defaultValue()));
169     d->coeffInput->setValue(group.readEntry(d->configCoeffAdjustmentEntry,   d->coeffInput->defaultValue()));
170 
171     blockWidgetSignals(false);
172 }
173 
writeSettings()174 void RainDropTool::writeSettings()
175 {
176     KSharedConfig::Ptr config = KSharedConfig::openConfig();
177     KConfigGroup group        = config->group(d->configGroupName);
178     group.writeEntry(d->configDropAdjustmentEntry,   d->dropInput->value());
179     group.writeEntry(d->configAmountAdjustmentEntry, d->amountInput->value());
180     group.writeEntry(d->configCoeffAdjustmentEntry,  d->coeffInput->value());
181 
182     group.sync();
183 }
184 
slotResetSettings()185 void RainDropTool::slotResetSettings()
186 {
187     blockWidgetSignals(true);
188 
189     d->dropInput->slotReset();
190     d->amountInput->slotReset();
191     d->coeffInput->slotReset();
192 
193     blockWidgetSignals(false);
194 
195     slotPreview();
196 }
197 
preparePreview()198 void RainDropTool::preparePreview()
199 {
200     int drop                = d->dropInput->value();
201     int amount              = d->amountInput->value();
202     int coeff               = d->coeffInput->value();
203 
204     ImageIface* const iface = d->previewWidget->imageIface();
205 
206     // Selected data from the image
207     QRect selection         = iface->selectionRect();
208 
209     setFilter(new RainDropFilter(iface->original(), this, drop, amount, coeff, selection));
210 }
211 
prepareFinal()212 void RainDropTool::prepareFinal()
213 {
214     int drop        = d->dropInput->value();
215     int amount      = d->amountInput->value();
216     int coeff       = d->coeffInput->value();
217 
218     ImageIface iface;
219 
220     // Selected data from the image
221     QRect selection = iface.selectionRect();
222 
223     setFilter(new RainDropFilter(iface.original(), this, drop, amount, coeff, selection));
224 }
225 
setPreviewImage()226 void RainDropTool::setPreviewImage()
227 {
228     ImageIface* const iface = d->previewWidget->imageIface();
229     DImg imDest             = filter()->getTargetImage().smoothScale(iface->previewSize());
230     iface->setPreview(imDest);
231 
232     d->previewWidget->updatePreview();
233 }
234 
setFinalImage()235 void RainDropTool::setFinalImage()
236 {
237     ImageIface iface;
238     iface.setOriginal(i18n("RainDrop"), filter()->filterAction(), filter()->getTargetImage());
239 }
240 
blockWidgetSignals(bool b)241 void RainDropTool::blockWidgetSignals(bool b)
242 {
243     d->dropInput->blockSignals(b);
244     d->amountInput->blockSignals(b);
245     d->coeffInput->blockSignals(b);
246 }
247 
248 } // namespace DigikamEditorRainDropToolPlugin
249