1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2005-02-14
7 * Description : a tool to insert a text over an image.
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 "inserttexttool.h"
26
27 // Qt includes
28
29 #include <QBrush>
30 #include <QButtonGroup>
31 #include <QCheckBox>
32 #include <QFont>
33 #include <QFrame>
34 #include <QGridLayout>
35 #include <QGroupBox>
36 #include <QLabel>
37 #include <QPainter>
38 #include <QPen>
39 #include <QPixmap>
40 #include <QTimer>
41 #include <QToolButton>
42 #include <QVBoxLayout>
43 #include <QIcon>
44 #include <QComboBox>
45 #include <QApplication>
46 #include <QTextEdit>
47
48 // KDE includes
49
50 #include <klocalizedstring.h>
51 #include <ksharedconfig.h>
52 #include <kconfiggroup.h>
53
54 // Local includes
55
56 #include "dlayoutbox.h"
57 #include "dimg.h"
58 #include "editortoolsettings.h"
59 #include "imageiface.h"
60 #include "inserttextwidget.h"
61 #include "dfontproperties.h"
62 #include "dcolorselector.h"
63 #include "dnuminput.h"
64
65 namespace DigikamEditorInsertTextToolPlugin
66 {
67
68 class Q_DECL_HIDDEN InsertTextTool::Private
69 {
70 public:
71
Private()72 explicit Private()
73 : alignTextMode (0),
74 defaultSizeFont (0),
75 borderText (nullptr),
76 transparentText (nullptr),
77 alignButtonGroup (nullptr),
78 textRotation (nullptr),
79 textOpacity (nullptr),
80 fontColorButton (nullptr),
81 fontChooserWidget (nullptr),
82 textEdit (nullptr),
83 previewWidget (nullptr),
84 gboxSettings (nullptr)
85 {
86 }
87
88 static const QString configGroupName;
89 static const QString configTextRotationEntry;
90 static const QString configFontColorEntry;
91 static const QString configTextOpacity;
92 static const QString configTextStringEntry;
93 static const QString configFontPropertiesEntry;
94 static const QString configTextAlignmentEntry;
95 static const QString configBorderTextEntry;
96 static const QString configTransparentTextEntry;
97 static const QString configPositionHintEntry;
98
99 int alignTextMode;
100 int defaultSizeFont;
101
102 QCheckBox* borderText;
103 QCheckBox* transparentText;
104
105 QButtonGroup* alignButtonGroup;
106 QFont textFont;
107
108 QComboBox* textRotation;
109 DIntNumInput* textOpacity;
110 DColorSelector* fontColorButton;
111 DFontProperties* fontChooserWidget;
112 QTextEdit* textEdit;
113
114 InsertTextWidget* previewWidget;
115 EditorToolSettings* gboxSettings;
116 };
117
118 const QString InsertTextTool::Private::configGroupName(QLatin1String("inserttext Tool"));
119 const QString InsertTextTool::Private::configTextRotationEntry(QLatin1String("Text Rotation"));
120 const QString InsertTextTool::Private::configFontColorEntry(QLatin1String("Font Color"));
121 const QString InsertTextTool::Private::configTextOpacity(QLatin1String("Text Opacity"));
122 const QString InsertTextTool::Private::configTextStringEntry(QLatin1String("Enter your text here."));
123 const QString InsertTextTool::Private::configFontPropertiesEntry(QLatin1String("Font Properties"));
124 const QString InsertTextTool::Private::configTextAlignmentEntry(QLatin1String("Text Alignment"));
125 const QString InsertTextTool::Private::configBorderTextEntry(QLatin1String("Border Text"));
126 const QString InsertTextTool::Private::configTransparentTextEntry(QLatin1String("Transparent Text"));
127 const QString InsertTextTool::Private::configPositionHintEntry(QLatin1String("Position Hint"));
128
129 // --------------------------------------------------------
130
InsertTextTool(QObject * const parent)131 InsertTextTool::InsertTextTool(QObject* const parent)
132 : EditorTool(parent),
133 d (new Private)
134 {
135 setObjectName(QLatin1String("inserttext"));
136
137 // -------------------------------------------------------------
138
139 QFrame* const frame = new QFrame(nullptr);
140 frame->setFrameStyle(QFrame::Panel|QFrame::Sunken);
141
142 QVBoxLayout* const l = new QVBoxLayout(frame);
143 d->previewWidget = new InsertTextWidget(480, 320, frame);
144 l->addWidget(d->previewWidget);
145 d->previewWidget->setWhatsThis(i18n("This previews the text inserted in the image. "
146 "You can use the mouse to move the text to the right location."));
147 setToolView(frame);
148
149 // -------------------------------------------------------------
150
151 d->gboxSettings = new EditorToolSettings(nullptr);
152 d->textEdit = new QTextEdit();
153 d->textEdit->setWordWrapMode(QTextOption::NoWrap);
154 d->textEdit->setWhatsThis( i18n("Here, enter the text you want to insert in your image."));
155
156 // -------------------------------------------------------------
157
158 d->fontChooserWidget = new DFontProperties(nullptr, DFontProperties::NoDisplayFlags);
159 d->fontChooserWidget->setSampleBoxVisible(false);
160 d->fontChooserWidget->setWhatsThis(i18n("Here you can choose the font to be used."));
161
162 // -------------------------------------------------------------
163
164 QWidget* const alignBox = new QWidget();
165 QHBoxLayout* const hlay = new QHBoxLayout(alignBox);
166 d->alignButtonGroup = new QButtonGroup(alignBox);
167 d->alignButtonGroup->setExclusive(true);
168
169 QToolButton* const alignLeft = new QToolButton(alignBox);
170 d->alignButtonGroup->addButton(alignLeft, InsertTextWidget::ALIGN_LEFT);
171 alignLeft->setIcon(QIcon::fromTheme(QLatin1String("format-justify-left")));
172 alignLeft->setCheckable(true);
173 alignLeft->setToolTip(i18n("Align text to the left"));
174
175 QToolButton* const alignRight = new QToolButton(alignBox);
176 d->alignButtonGroup->addButton(alignRight, InsertTextWidget::ALIGN_RIGHT);
177 alignRight->setIcon(QIcon::fromTheme(QLatin1String("format-justify-right")));
178 alignRight->setCheckable(true);
179 alignRight->setToolTip(i18n("Align text to the right"));
180
181 QToolButton* const alignCenter = new QToolButton(alignBox);
182 d->alignButtonGroup->addButton(alignCenter, InsertTextWidget::ALIGN_CENTER);
183 alignCenter->setIcon(QIcon::fromTheme(QLatin1String("format-justify-center")));
184 alignCenter->setCheckable(true);
185 alignCenter->setToolTip(i18n("Align text to center"));
186
187 QToolButton* alignBlock = new QToolButton(alignBox);
188 d->alignButtonGroup->addButton(alignBlock, InsertTextWidget::ALIGN_BLOCK);
189 alignBlock->setIcon(QIcon::fromTheme(QLatin1String("format-justify-fill")));
190 alignBlock->setCheckable(true);
191 alignBlock->setToolTip(i18n("Align text to a block"));
192
193 hlay->setContentsMargins(QMargins());
194 hlay->setSpacing(0);
195 hlay->addStretch();
196 hlay->addWidget(alignLeft);
197 hlay->addWidget(alignRight);
198 hlay->addWidget(alignCenter);
199 hlay->addWidget(alignBlock);
200 hlay->addStretch();
201
202 // -------------------------------------------------------------
203
204 QLabel* const label1 = new QLabel(i18n("Rotation:"));
205 d->textRotation = new QComboBox();
206 d->textRotation->addItem(i18nc("no rotation", "None"));
207 d->textRotation->addItem(i18n("90 Degrees"));
208 d->textRotation->addItem(i18n("180 Degrees"));
209 d->textRotation->addItem(i18n("270 Degrees"));
210 d->textRotation->setWhatsThis(i18n("Select the text rotation to use here."));
211
212 // -------------------------------------------------------------
213
214 QLabel* const label2 = new QLabel(i18nc("font color", "Color:"));
215 d->fontColorButton = new DColorSelector();
216 d->fontColorButton->setColor(Qt::black);
217 d->fontColorButton->setWhatsThis(i18n("Set here the font color to use."));
218
219 // -------------------------------------------------------------
220
221 QLabel* const label3 = new QLabel(i18nc("text opacity", "Opacity:"));
222 d->textOpacity = new DIntNumInput();
223 d->textOpacity->setRange(0, 100, 1);
224 d->textOpacity->setDefaultValue(100);
225 d->textOpacity->setSuffix(QLatin1String("%"));
226 d->textOpacity->setWhatsThis(i18n("Select the text opacity to use here."));
227
228 // -------------------------------------------------------------
229
230 d->borderText = new QCheckBox(i18n("Add border"));
231 d->borderText->setToolTip(i18n("Add a solid border around text using current text color"));
232
233 d->transparentText = new QCheckBox(i18n("Semi-transparent"));
234 d->transparentText->setToolTip(i18n("Use semi-transparent text background under image"));
235
236 // -------------------------------------------------------------
237
238 const int spacing = d->gboxSettings->spacingHint();
239
240 QGridLayout* const mainLayout = new QGridLayout();
241 mainLayout->addWidget(d->textEdit, 0, 0, 3, -1);
242 mainLayout->addWidget(d->fontChooserWidget, 3, 0, 1, -1);
243 mainLayout->addWidget(alignBox, 4, 0, 1, -1);
244 mainLayout->addWidget(label1, 5, 0, 1, 1);
245 mainLayout->addWidget(d->textRotation, 5, 1, 1, 1);
246 mainLayout->addWidget(label2, 6, 0, 1, 1);
247 mainLayout->addWidget(d->fontColorButton, 6, 1, 1, 1);
248 mainLayout->addWidget(label3, 7, 0, 1, 1);
249 mainLayout->addWidget(d->textOpacity, 7, 1, 1, 1);
250 mainLayout->addWidget(d->borderText, 8, 0, 1, -1);
251 mainLayout->addWidget(d->transparentText, 9, 0, 1, -1);
252 mainLayout->setRowStretch(10, 10);
253 mainLayout->setColumnStretch(1, 5);
254 mainLayout->setColumnStretch(2, 10);
255 mainLayout->setContentsMargins(spacing, spacing, spacing, spacing);
256 mainLayout->setSpacing(spacing);
257 d->gboxSettings->plainPage()->setLayout(mainLayout);
258
259 // -------------------------------------------------------------
260
261 setToolSettings(d->gboxSettings);
262
263 // -------------------------------------------------------------
264
265 connect(d->fontChooserWidget, SIGNAL(fontSelected(QFont)),
266 this, SLOT(slotFontPropertiesChanged(QFont)));
267
268 connect(d->fontColorButton, SIGNAL(signalColorSelected(QColor)),
269 this, SLOT(slotUpdatePreview()));
270
271 connect(d->textOpacity, SIGNAL(valueChanged(int)),
272 this, SLOT(slotUpdatePreview()));
273
274 connect(d->textEdit, SIGNAL(textChanged()),
275 this, SLOT(slotUpdatePreview()));
276
277 connect(d->alignButtonGroup, SIGNAL(buttonReleased(int)),
278 this, SLOT(slotAlignModeChanged(int)));
279
280 connect(d->borderText, SIGNAL(toggled(bool)),
281 this, SLOT(slotUpdatePreview()));
282
283 connect(d->transparentText, SIGNAL(toggled(bool)),
284 this, SLOT(slotUpdatePreview()));
285
286 connect(d->textRotation, SIGNAL(activated(int)),
287 this, SLOT(slotUpdatePreview()));
288
289 connect(this, SIGNAL(signalUpdatePreview()),
290 this, SLOT(slotUpdatePreview()));
291
292 // -------------------------------------------------------------
293
294 slotUpdatePreview();
295 }
296
~InsertTextTool()297 InsertTextTool::~InsertTextTool()
298 {
299 delete d;
300 }
301
readSettings()302 void InsertTextTool::readSettings()
303 {
304 KSharedConfig::Ptr config = KSharedConfig::openConfig();
305 KConfigGroup group = config->group(d->configGroupName);
306 QColor black(0, 0, 0);
307 QFont defaultFont;
308
309 int orgW = d->previewWidget->imageIface()->originalSize().width();
310 int orgH = d->previewWidget->imageIface()->originalSize().height();
311
312 if ( orgW > orgH )
313 {
314 d->defaultSizeFont = (int)(orgH / 8.0);
315 }
316 else
317 {
318 d->defaultSizeFont = (int)(orgW / 8.0);
319 }
320
321 defaultFont.setPointSize(d->defaultSizeFont);
322
323 d->textRotation->setCurrentIndex(group.readEntry(d->configTextRotationEntry, 0));
324 d->fontColorButton->setColor(group.readEntry(d->configFontColorEntry, black));
325 d->textOpacity->setValue(group.readEntry(d->configTextOpacity, 100));
326 d->textEdit->setText(group.readEntry(d->configTextStringEntry, i18n("Enter your text here.")));
327 d->textFont = group.readEntry(d->configFontPropertiesEntry, defaultFont);
328 d->fontChooserWidget->setFont(d->textFont);
329 d->alignTextMode = group.readEntry(d->configTextAlignmentEntry, (int) InsertTextWidget::ALIGN_LEFT);
330 d->borderText->setChecked(group.readEntry(d->configBorderTextEntry, false));
331 d->transparentText->setChecked(group.readEntry(d->configTransparentTextEntry, false));
332 d->previewWidget->setPositionHint(group.readEntry(d->configPositionHintEntry, QRect()));
333
334 d->alignButtonGroup->button(d->alignTextMode)->setChecked(true);
335 slotAlignModeChanged(d->alignTextMode);
336 }
337
writeSettings()338 void InsertTextTool::writeSettings()
339 {
340 KSharedConfig::Ptr config = KSharedConfig::openConfig();
341 KConfigGroup group = config->group(d->configGroupName);
342
343 group.writeEntry(d->configTextRotationEntry, d->textRotation->currentIndex());
344 group.writeEntry(d->configFontColorEntry, d->fontColorButton->color());
345 group.writeEntry(d->configTextOpacity, d->textOpacity->value());
346 group.writeEntry(d->configTextStringEntry, d->textEdit->toPlainText());
347 group.writeEntry(d->configFontPropertiesEntry, d->textFont);
348 group.writeEntry(d->configTextAlignmentEntry, d->alignTextMode);
349 group.writeEntry(d->configBorderTextEntry, d->borderText->isChecked());
350 group.writeEntry(d->configTransparentTextEntry, d->transparentText->isChecked());
351 group.writeEntry(d->configPositionHintEntry, d->previewWidget->getPositionHint());
352
353 config->sync();
354 }
355
slotResetSettings()356 void InsertTextTool::slotResetSettings()
357 {
358 d->fontColorButton->blockSignals(true);
359 d->alignButtonGroup->blockSignals(true);
360 d->fontChooserWidget->blockSignals(true);
361
362 d->textRotation->setCurrentIndex(0); // No rotation.
363 d->fontColorButton->setColor(Qt::black);
364 d->textOpacity->slotReset();
365 QFont defaultFont;
366 d->textFont = defaultFont; // Reset to default KDE font.
367 d->textFont.setPointSize(d->defaultSizeFont);
368 d->fontChooserWidget->setFont(d->textFont);
369 d->borderText->setChecked(false);
370 d->transparentText->setChecked(false);
371 d->previewWidget->resetEdit();
372 d->alignButtonGroup->button(InsertTextWidget::ALIGN_LEFT)->setChecked(true);
373
374 d->fontChooserWidget->blockSignals(false);
375 d->fontColorButton->blockSignals(false);
376 d->alignButtonGroup->blockSignals(false);
377 slotAlignModeChanged(InsertTextWidget::ALIGN_LEFT);
378 }
379
slotAlignModeChanged(int mode)380 void InsertTextTool::slotAlignModeChanged(int mode)
381 {
382 d->alignTextMode = mode;
383 d->textEdit->selectAll();
384
385 switch (d->alignTextMode)
386 {
387 case InsertTextWidget::ALIGN_LEFT:
388 d->textEdit->setAlignment(Qt::AlignLeft);
389 break;
390
391 case InsertTextWidget::ALIGN_RIGHT:
392 d->textEdit->setAlignment(Qt::AlignRight);
393 break;
394
395 case InsertTextWidget::ALIGN_CENTER:
396 d->textEdit->setAlignment(Qt::AlignHCenter);
397 break;
398
399 case InsertTextWidget::ALIGN_BLOCK:
400 d->textEdit->setAlignment(Qt::AlignJustify);
401 break;
402 }
403
404 d->textEdit->textCursor().clearSelection();
405 emit signalUpdatePreview();
406 }
407
slotFontPropertiesChanged(const QFont & font)408 void InsertTextTool::slotFontPropertiesChanged(const QFont& font)
409 {
410 d->textFont = font;
411 emit signalUpdatePreview();
412 }
413
setBackgroundColor(const QColor & bg)414 void InsertTextTool::setBackgroundColor(const QColor& bg)
415 {
416 d->previewWidget->setBackgroundColor(bg);
417 }
418
slotUpdatePreview()419 void InsertTextTool::slotUpdatePreview()
420 {
421 d->previewWidget->setText(d->textEdit->toPlainText(), d->textFont, d->fontColorButton->color(),
422 d->textOpacity->value(), d->alignTextMode,
423 d->borderText->isChecked(), d->transparentText->isChecked(),
424 d->textRotation->currentIndex());
425 }
426
finalRendering()427 void InsertTextTool::finalRendering()
428 {
429 qApp->setOverrideCursor( Qt::WaitCursor );
430
431 ImageIface iface;
432 DImg dest = d->previewWidget->makeInsertText();
433
434 FilterAction action(QLatin1String("digikam:insertTextTool"), 2);
435 action.setDisplayableName(i18n("Insert Text Tool"));
436
437 action.addParameter(QLatin1String("text"), d->textEdit->toPlainText());
438 action.addParameter(QLatin1String("textRotationIndex"), d->textRotation->currentIndex());
439 action.addParameter(QLatin1String("textFont"), d->textFont.toString());
440 action.addParameter(QLatin1String("colorR"), d->fontColorButton->color().red());
441 action.addParameter(QLatin1String("colorG"), d->fontColorButton->color().green());
442 action.addParameter(QLatin1String("colorB"), d->fontColorButton->color().blue());
443 action.addParameter(QLatin1String("colorA"), d->fontColorButton->color().alpha());
444 action.addParameter(QLatin1String("textOpacity"), d->textOpacity->value());
445 action.addParameter(QLatin1String("borderText"), d->borderText->isChecked());
446 action.addParameter(QLatin1String("transparentText"), d->transparentText->isChecked());
447
448 iface.setOriginal(i18n("Insert Text"), action, dest);
449
450 qApp->restoreOverrideCursor();
451 }
452
453 } // namespace DigikamEditorInsertTextToolPlugin
454