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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2005-02-14
0007  * Description : a tool to insert a text over an image.
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 "inserttexttool.h"
0017 
0018 // Qt includes
0019 
0020 #include <QBrush>
0021 #include <QButtonGroup>
0022 #include <QCheckBox>
0023 #include <QFont>
0024 #include <QFrame>
0025 #include <QGridLayout>
0026 #include <QGroupBox>
0027 #include <QLabel>
0028 #include <QPainter>
0029 #include <QPen>
0030 #include <QPixmap>
0031 #include <QTimer>
0032 #include <QToolButton>
0033 #include <QVBoxLayout>
0034 #include <QIcon>
0035 #include <QComboBox>
0036 #include <QApplication>
0037 
0038 // KDE includes
0039 
0040 #include <klocalizedstring.h>
0041 #include <ksharedconfig.h>
0042 #include <kconfiggroup.h>
0043 
0044 // Local includes
0045 
0046 #include "dlayoutbox.h"
0047 #include "dimg.h"
0048 #include "editortoolsettings.h"
0049 #include "imageiface.h"
0050 #include "inserttextwidget.h"
0051 #include "dfontproperties.h"
0052 #include "dcolorselector.h"
0053 #include "dnuminput.h"
0054 #include "dtextedit.h"
0055 
0056 namespace DigikamEditorInsertTextToolPlugin
0057 {
0058 
0059 class Q_DECL_HIDDEN InsertTextTool::Private
0060 {
0061 public:
0062 
0063     explicit Private()
0064       : alignTextMode       (0),
0065         defaultSizeFont     (0),
0066         borderText          (nullptr),
0067         transparentText     (nullptr),
0068         alignButtonGroup    (nullptr),
0069         textRotation        (nullptr),
0070         textOpacity         (nullptr),
0071         fontColorButton     (nullptr),
0072         fontChooserWidget   (nullptr),
0073         textEdit            (nullptr),
0074         previewWidget       (nullptr),
0075         gboxSettings        (nullptr)
0076     {
0077     }
0078 
0079     static const QString configGroupName;
0080     static const QString configTextRotationEntry;
0081     static const QString configFontColorEntry;
0082     static const QString configTextOpacity;
0083     static const QString configTextStringEntry;
0084     static const QString configFontPropertiesEntry;
0085     static const QString configTextAlignmentEntry;
0086     static const QString configBorderTextEntry;
0087     static const QString configTransparentTextEntry;
0088     static const QString configPositionHintEntry;
0089 
0090     int                  alignTextMode;
0091     int                  defaultSizeFont;
0092 
0093     QCheckBox*           borderText;
0094     QCheckBox*           transparentText;
0095 
0096     QButtonGroup*        alignButtonGroup;
0097     QFont                textFont;
0098 
0099     QComboBox*           textRotation;
0100     DIntNumInput*        textOpacity;
0101     DColorSelector*      fontColorButton;
0102     DFontProperties*     fontChooserWidget;
0103     DTextEdit*           textEdit;
0104 
0105     InsertTextWidget*    previewWidget;
0106     EditorToolSettings*  gboxSettings;
0107 };
0108 
0109 const QString InsertTextTool::Private::configGroupName(QLatin1String("inserttext Tool"));
0110 const QString InsertTextTool::Private::configTextRotationEntry(QLatin1String("Text Rotation"));
0111 const QString InsertTextTool::Private::configFontColorEntry(QLatin1String("Font Color"));
0112 const QString InsertTextTool::Private::configTextOpacity(QLatin1String("Text Opacity"));
0113 const QString InsertTextTool::Private::configTextStringEntry(QLatin1String("Enter your text here."));
0114 const QString InsertTextTool::Private::configFontPropertiesEntry(QLatin1String("Font Properties"));
0115 const QString InsertTextTool::Private::configTextAlignmentEntry(QLatin1String("Text Alignment"));
0116 const QString InsertTextTool::Private::configBorderTextEntry(QLatin1String("Border Text"));
0117 const QString InsertTextTool::Private::configTransparentTextEntry(QLatin1String("Transparent Text"));
0118 const QString InsertTextTool::Private::configPositionHintEntry(QLatin1String("Position Hint"));
0119 
0120 // --------------------------------------------------------
0121 
0122 InsertTextTool::InsertTextTool(QObject* const parent)
0123     : EditorTool(parent),
0124       d         (new Private)
0125 {
0126     setObjectName(QLatin1String("inserttext"));
0127 
0128     // -------------------------------------------------------------
0129 
0130     QFrame* const frame  = new QFrame(nullptr);
0131     frame->setFrameStyle(QFrame::Panel|QFrame::Sunken);
0132 
0133     QVBoxLayout* const l = new QVBoxLayout(frame);
0134     d->previewWidget     = new InsertTextWidget(480, 320, frame);
0135     l->addWidget(d->previewWidget);
0136     d->previewWidget->setWhatsThis(i18n("This previews the text inserted in the image. "
0137                                         "You can use the mouse to move the text to the right location."));
0138     setToolView(frame);
0139 
0140     // -------------------------------------------------------------
0141 
0142     d->gboxSettings = new EditorToolSettings(nullptr);
0143     d->textEdit     = new DTextEdit();
0144     d->textEdit->setWordWrapMode(QTextOption::NoWrap);
0145     d->textEdit->setWhatsThis(i18n("Here, enter the text you want to insert in your image."));
0146 
0147     // -------------------------------------------------------------
0148 
0149     d->fontChooserWidget = new DFontProperties(nullptr, DFontProperties::NoDisplayFlags);
0150     d->fontChooserWidget->setSampleBoxVisible(false);
0151     d->fontChooserWidget->setWhatsThis(i18n("Here you can choose the font to be used."));
0152 
0153     // -------------------------------------------------------------
0154 
0155     QWidget* const alignBox   = new QWidget();
0156     QHBoxLayout* const hlay   = new QHBoxLayout(alignBox);
0157     d->alignButtonGroup       = new QButtonGroup(alignBox);
0158     d->alignButtonGroup->setExclusive(true);
0159 
0160     QToolButton* const alignLeft = new QToolButton(alignBox);
0161     d->alignButtonGroup->addButton(alignLeft, InsertTextWidget::ALIGN_LEFT);
0162     alignLeft->setIcon(QIcon::fromTheme(QLatin1String("format-justify-left")));
0163     alignLeft->setCheckable(true);
0164     alignLeft->setToolTip(i18n("Align text to the left"));
0165 
0166     QToolButton* const alignRight = new QToolButton(alignBox);
0167     d->alignButtonGroup->addButton(alignRight, InsertTextWidget::ALIGN_RIGHT);
0168     alignRight->setIcon(QIcon::fromTheme(QLatin1String("format-justify-right")));
0169     alignRight->setCheckable(true);
0170     alignRight->setToolTip(i18n("Align text to the right"));
0171 
0172     QToolButton* const alignCenter = new QToolButton(alignBox);
0173     d->alignButtonGroup->addButton(alignCenter, InsertTextWidget::ALIGN_CENTER);
0174     alignCenter->setIcon(QIcon::fromTheme(QLatin1String("format-justify-center")));
0175     alignCenter->setCheckable(true);
0176     alignCenter->setToolTip(i18n("Align text to center"));
0177 
0178     QToolButton* alignBlock = new QToolButton(alignBox);
0179     d->alignButtonGroup->addButton(alignBlock, InsertTextWidget::ALIGN_BLOCK);
0180     alignBlock->setIcon(QIcon::fromTheme(QLatin1String("format-justify-fill")));
0181     alignBlock->setCheckable(true);
0182     alignBlock->setToolTip(i18n("Align text to a block"));
0183 
0184     hlay->setContentsMargins(QMargins());
0185     hlay->setSpacing(0);
0186     hlay->addStretch();
0187     hlay->addWidget(alignLeft);
0188     hlay->addWidget(alignRight);
0189     hlay->addWidget(alignCenter);
0190     hlay->addWidget(alignBlock);
0191     hlay->addStretch();
0192 
0193     // -------------------------------------------------------------
0194 
0195     QLabel* const label1 = new QLabel(i18n("Rotation:"));
0196     d->textRotation      = new QComboBox();
0197     d->textRotation->addItem(i18nc("no rotation", "None"));
0198     d->textRotation->addItem(i18n("90 Degrees"));
0199     d->textRotation->addItem(i18n("180 Degrees"));
0200     d->textRotation->addItem(i18n("270 Degrees"));
0201     d->textRotation->setWhatsThis(i18n("Select the text rotation to use here."));
0202 
0203     // -------------------------------------------------------------
0204 
0205     QLabel* const label2 = new QLabel(i18nc("font color", "Color:"));
0206     d->fontColorButton   = new DColorSelector();
0207     d->fontColorButton->setColor(Qt::black);
0208     d->fontColorButton->setWhatsThis(i18n("Set here the font color to use."));
0209 
0210     // -------------------------------------------------------------
0211 
0212     QLabel* const label3 = new QLabel(i18nc("text opacity", "Opacity:"));
0213     d->textOpacity       = new DIntNumInput();
0214     d->textOpacity->setRange(0, 100, 1);
0215     d->textOpacity->setDefaultValue(100);
0216     d->textOpacity->setSuffix(QLatin1String("%"));
0217     d->textOpacity->setWhatsThis(i18n("Select the text opacity to use here."));
0218 
0219     // -------------------------------------------------------------
0220 
0221     d->borderText      = new QCheckBox(i18n("Add border"));
0222     d->borderText->setToolTip(i18n("Add a solid border around text using current text color"));
0223 
0224     d->transparentText = new QCheckBox(i18n("Semi-transparent"));
0225     d->transparentText->setToolTip(i18n("Use semi-transparent text background under image"));
0226 
0227     // -------------------------------------------------------------
0228 
0229     const int spacing = d->gboxSettings->spacingHint();
0230 
0231     QGridLayout* const mainLayout = new QGridLayout();
0232     mainLayout->addWidget(d->textEdit,             0, 0, 3, -1);
0233     mainLayout->addWidget(d->fontChooserWidget,    3, 0, 1, -1);
0234     mainLayout->addWidget(alignBox,                4, 0, 1, -1);
0235     mainLayout->addWidget(label1,                  5, 0, 1,  1);
0236     mainLayout->addWidget(d->textRotation,         5, 1, 1,  1);
0237     mainLayout->addWidget(label2,                  6, 0, 1,  1);
0238     mainLayout->addWidget(d->fontColorButton,      6, 1, 1,  1);
0239     mainLayout->addWidget(label3,                  7, 0, 1,  1);
0240     mainLayout->addWidget(d->textOpacity,          7, 1, 1,  1);
0241     mainLayout->addWidget(d->borderText,           8, 0, 1, -1);
0242     mainLayout->addWidget(d->transparentText,      9, 0, 1, -1);
0243     mainLayout->setRowStretch(10, 10);
0244     mainLayout->setColumnStretch(1, 5);
0245     mainLayout->setColumnStretch(2, 10);
0246     mainLayout->setContentsMargins(spacing, spacing, spacing, spacing);
0247     mainLayout->setSpacing(spacing);
0248     d->gboxSettings->plainPage()->setLayout(mainLayout);
0249 
0250     // -------------------------------------------------------------
0251 
0252     setToolSettings(d->gboxSettings);
0253 
0254     // -------------------------------------------------------------
0255 
0256     connect(d->fontChooserWidget, SIGNAL(fontSelected(QFont)),
0257             this, SLOT(slotFontPropertiesChanged(QFont)));
0258 
0259     connect(d->fontColorButton, SIGNAL(signalColorSelected(QColor)),
0260             this, SLOT(slotUpdatePreview()));
0261 
0262     connect(d->textOpacity, SIGNAL(valueChanged(int)),
0263             this, SLOT(slotUpdatePreview()));
0264 
0265     connect(d->textEdit, SIGNAL(textChanged()),
0266             this, SLOT(slotUpdatePreview()));
0267 
0268 #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
0269 
0270     connect(d->alignButtonGroup, SIGNAL(idReleased(int)),
0271             this, SLOT(slotAlignModeChanged(int)));
0272 
0273 #else
0274 
0275     connect(d->alignButtonGroup, SIGNAL(buttonReleased(int)),
0276             this, SLOT(slotAlignModeChanged(int)));
0277 
0278 #endif
0279 
0280     connect(d->borderText, SIGNAL(toggled(bool)),
0281             this, SLOT(slotUpdatePreview()));
0282 
0283     connect(d->transparentText, SIGNAL(toggled(bool)),
0284             this, SLOT(slotUpdatePreview()));
0285 
0286     connect(d->textRotation, SIGNAL(activated(int)),
0287             this, SLOT(slotUpdatePreview()));
0288 
0289     connect(this, SIGNAL(signalUpdatePreview()),
0290             this, SLOT(slotUpdatePreview()));
0291 
0292     // -------------------------------------------------------------
0293 
0294     slotUpdatePreview();
0295 }
0296 
0297 InsertTextTool::~InsertTextTool()
0298 {
0299     delete d;
0300 }
0301 
0302 void InsertTextTool::readSettings()
0303 {
0304     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0305     KConfigGroup group        = config->group(d->configGroupName);
0306     QColor black(0, 0, 0);
0307     QFont  defaultFont;
0308 
0309     int orgW = d->previewWidget->imageIface()->originalSize().width();
0310     int orgH = d->previewWidget->imageIface()->originalSize().height();
0311 
0312     if ( orgW > orgH )
0313     {
0314         d->defaultSizeFont = (int)(orgH / 8.0);
0315     }
0316     else
0317     {
0318         d->defaultSizeFont = (int)(orgW / 8.0);
0319     }
0320 
0321     defaultFont.setPointSize(d->defaultSizeFont);
0322 
0323     d->textRotation->setCurrentIndex(group.readEntry(d->configTextRotationEntry,  0));
0324     d->fontColorButton->setColor(group.readEntry(d->configFontColorEntry,         black));
0325     d->textOpacity->setValue(group.readEntry(d->configTextOpacity,                100));
0326     d->textEdit->setText(group.readEntry(d->configTextStringEntry,                i18n("Enter your text here.")));
0327     d->textFont = group.readEntry(d->configFontPropertiesEntry,                   defaultFont);
0328     d->fontChooserWidget->setFont(d->textFont);
0329     d->alignTextMode = group.readEntry(d->configTextAlignmentEntry,               (int) InsertTextWidget::ALIGN_LEFT);
0330     d->borderText->setChecked(group.readEntry(d->configBorderTextEntry,           false));
0331     d->transparentText->setChecked(group.readEntry(d->configTransparentTextEntry, false));
0332     d->previewWidget->setPositionHint(group.readEntry(d->configPositionHintEntry, QRect()));
0333 
0334     d->alignButtonGroup->button(d->alignTextMode)->setChecked(true);
0335     slotAlignModeChanged(d->alignTextMode);
0336 }
0337 
0338 void InsertTextTool::writeSettings()
0339 {
0340     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0341     KConfigGroup group        = config->group(d->configGroupName);
0342 
0343     group.writeEntry(d->configTextRotationEntry,    d->textRotation->currentIndex());
0344     group.writeEntry(d->configFontColorEntry,       d->fontColorButton->color());
0345     group.writeEntry(d->configTextOpacity,          d->textOpacity->value());
0346     group.writeEntry(d->configTextStringEntry,      d->textEdit->toPlainText());
0347     group.writeEntry(d->configFontPropertiesEntry,  d->textFont);
0348     group.writeEntry(d->configTextAlignmentEntry,   d->alignTextMode);
0349     group.writeEntry(d->configBorderTextEntry,      d->borderText->isChecked());
0350     group.writeEntry(d->configTransparentTextEntry, d->transparentText->isChecked());
0351     group.writeEntry(d->configPositionHintEntry,    d->previewWidget->getPositionHint());
0352 
0353     config->sync();
0354 }
0355 
0356 void InsertTextTool::slotResetSettings()
0357 {
0358     d->fontColorButton->blockSignals(true);
0359     d->alignButtonGroup->blockSignals(true);
0360     d->fontChooserWidget->blockSignals(true);
0361 
0362     d->textRotation->setCurrentIndex(0); // No rotation.
0363     d->fontColorButton->setColor(Qt::black);
0364     d->textOpacity->slotReset();
0365     QFont defaultFont;
0366     d->textFont = defaultFont;           // Reset to default KDE font.
0367     d->textFont.setPointSize(d->defaultSizeFont);
0368     d->fontChooserWidget->setFont(d->textFont);
0369     d->borderText->setChecked(false);
0370     d->transparentText->setChecked(false);
0371     d->previewWidget->resetEdit();
0372     d->alignButtonGroup->button(InsertTextWidget::ALIGN_LEFT)->setChecked(true);
0373 
0374     d->fontChooserWidget->blockSignals(false);
0375     d->fontColorButton->blockSignals(false);
0376     d->alignButtonGroup->blockSignals(false);
0377     slotAlignModeChanged(InsertTextWidget::ALIGN_LEFT);
0378 }
0379 
0380 void InsertTextTool::slotAlignModeChanged(int mode)
0381 {
0382     d->alignTextMode = mode;
0383     d->textEdit->selectAll();
0384 
0385     switch (d->alignTextMode)
0386     {
0387         case InsertTextWidget::ALIGN_LEFT:
0388             d->textEdit->setAlignment(Qt::AlignLeft);
0389             break;
0390 
0391         case InsertTextWidget::ALIGN_RIGHT:
0392             d->textEdit->setAlignment(Qt::AlignRight);
0393             break;
0394 
0395         case InsertTextWidget::ALIGN_CENTER:
0396             d->textEdit->setAlignment(Qt::AlignHCenter);
0397             break;
0398 
0399         case InsertTextWidget::ALIGN_BLOCK:
0400             d->textEdit->setAlignment(Qt::AlignJustify);
0401             break;
0402     }
0403 
0404     d->textEdit->textCursor().clearSelection();
0405     Q_EMIT signalUpdatePreview();
0406 }
0407 
0408 void InsertTextTool::slotFontPropertiesChanged(const QFont& font)
0409 {
0410     d->textFont = font;
0411     Q_EMIT signalUpdatePreview();
0412 }
0413 
0414 void InsertTextTool::setBackgroundColor(const QColor& bg)
0415 {
0416     d->previewWidget->setBackgroundColor(bg);
0417 }
0418 
0419 void InsertTextTool::slotUpdatePreview()
0420 {
0421     d->previewWidget->setText(d->textEdit->toPlainText(), d->textFont, d->fontColorButton->color(),
0422                               d->textOpacity->value(), d->alignTextMode,
0423                               d->borderText->isChecked(), d->transparentText->isChecked(),
0424                               d->textRotation->currentIndex());
0425 }
0426 
0427 void InsertTextTool::finalRendering()
0428 {
0429     qApp->setOverrideCursor( Qt::WaitCursor );
0430 
0431     ImageIface iface;
0432     DImg dest = d->previewWidget->makeInsertText();
0433 
0434     FilterAction action(QLatin1String("digikam:insertTextTool"), 2);
0435     action.setDisplayableName(i18n("Insert Text Tool"));
0436 
0437     action.addParameter(QLatin1String("text"),              d->textEdit->toPlainText());
0438     action.addParameter(QLatin1String("textRotationIndex"), d->textRotation->currentIndex());
0439     action.addParameter(QLatin1String("textFont"),          d->textFont.toString());
0440     action.addParameter(QLatin1String("colorR"),            d->fontColorButton->color().red());
0441     action.addParameter(QLatin1String("colorG"),            d->fontColorButton->color().green());
0442     action.addParameter(QLatin1String("colorB"),            d->fontColorButton->color().blue());
0443     action.addParameter(QLatin1String("colorA"),            d->fontColorButton->color().alpha());
0444     action.addParameter(QLatin1String("textOpacity"),       d->textOpacity->value());
0445     action.addParameter(QLatin1String("borderText"),        d->borderText->isChecked());
0446     action.addParameter(QLatin1String("transparentText"),   d->transparentText->isChecked());
0447 
0448     iface.setOriginal(i18n("Insert Text"), action, dest);
0449 
0450     qApp->restoreOverrideCursor();
0451 }
0452 
0453 } // namespace DigikamEditorInsertTextToolPlugin
0454 
0455 #include "moc_inserttexttool.cpp"