File indexing completed on 2024-05-12 16:34:29

0001 /* This file is part of the KDE project
0002  * Copyright (c) 2010 Jan Hambrecht <jaham@gmx.net>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2.1 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Library General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Lesser General Public License
0015  * along with this library; see the file COPYING.LIB.  If not, write to
0016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018  */
0019 
0020 #include "ConvolveMatrixEffectConfigWidget.h"
0021 #include "ConvolveMatrixEffect.h"
0022 #include "KoFilterEffect.h"
0023 #include "MatrixDataModel.h"
0024 
0025 #include <klocalizedstring.h>
0026 #include <kcombobox.h>
0027 #include <QDialog>
0028 
0029 #include <QGridLayout>
0030 #include <QLabel>
0031 #include <QDoubleSpinBox>
0032 #include <QPushButton>
0033 #include <QCheckBox>
0034 #include <QTableView>
0035 #include <QHeaderView>
0036 #include <KConfigGroup>
0037 #include <QDialogButtonBox>
0038 
0039 ConvolveMatrixEffectConfigWidget::ConvolveMatrixEffectConfigWidget(QWidget *parent)
0040         : KoFilterEffectConfigWidgetBase(parent), m_effect(0)
0041 {
0042     QGridLayout * g = new QGridLayout(this);
0043 
0044     m_edgeMode = new KComboBox(this);
0045     m_edgeMode->addItem(i18n("Duplicate"));
0046     m_edgeMode->addItem(i18n("Wrap"));
0047     m_edgeMode->addItem(i18n("None"));
0048     g->addWidget(new QLabel(i18n("Edge mode:"), this), 0, 0);
0049     g->addWidget(m_edgeMode, 0, 1, 1, 3);
0050 
0051     m_orderX = new QSpinBox(this);
0052     m_orderX->setRange(1, 30);
0053     m_orderY = new QSpinBox(this);
0054     m_orderY->setRange(1, 30);
0055     g->addWidget(new QLabel(i18n("Kernel size:"), this), 1, 0);
0056     g->addWidget(m_orderX, 1, 1);
0057     g->addWidget(new QLabel("X", this), 1, 2, Qt::AlignHCenter);
0058     g->addWidget(m_orderY, 1, 3);
0059 
0060     m_targetX = new QSpinBox(this);
0061     m_targetX->setRange(0, 30);
0062     m_targetY = new QSpinBox(this);
0063     m_targetY->setRange(0, 30);
0064     g->addWidget(new QLabel(i18n("Target point:"), this), 2, 0);
0065     g->addWidget(m_targetX, 2, 1);
0066     g->addWidget(new QLabel("X", this), 2, 2, Qt::AlignHCenter);
0067     g->addWidget(m_targetY, 2, 3);
0068 
0069     m_divisor = new QDoubleSpinBox(this);
0070     m_bias = new QDoubleSpinBox(this);
0071     g->addWidget(new QLabel(i18n("Divisor:"), this), 3, 0);
0072     g->addWidget(m_divisor, 3, 1);
0073     g->addWidget(new QLabel(i18n("Bias:"), this), 3, 2);
0074     g->addWidget(m_bias, 3, 3);
0075 
0076     m_preserveAlpha = new QCheckBox(i18n("Preserve alpha"), this);
0077     g->addWidget(m_preserveAlpha, 4, 1, 1, 3);
0078 
0079     QPushButton * kernelButton = new QPushButton(i18n("Edit kernel"), this);
0080     g->addWidget(kernelButton, 5, 0, 1, 4);
0081 
0082     setLayout(g);
0083 
0084     connect(m_edgeMode, SIGNAL(currentIndexChanged(int)), this, SLOT(edgeModeChanged(int)));
0085     connect(m_orderX, SIGNAL(valueChanged(int)), this, SLOT(orderChanged(int)));
0086     connect(m_orderY, SIGNAL(valueChanged(int)), this, SLOT(orderChanged(int)));
0087     connect(m_targetX, SIGNAL(valueChanged(int)), this, SLOT(targetChanged(int)));
0088     connect(m_targetY, SIGNAL(valueChanged(int)), this, SLOT(targetChanged(int)));
0089     connect(m_divisor, SIGNAL(valueChanged(double)), this, SLOT(divisorChanged(double)));
0090     connect(m_bias, SIGNAL(valueChanged(double)), this, SLOT(biasChanged(double)));
0091     connect(kernelButton, SIGNAL(clicked(bool)), this, SLOT(editKernel()));
0092     connect(m_preserveAlpha, SIGNAL(toggled(bool)), this, SLOT(preserveAlphaChanged(bool)));
0093 
0094     m_matrixModel = new MatrixDataModel(this);
0095 }
0096 
0097 bool ConvolveMatrixEffectConfigWidget::editFilterEffect(KoFilterEffect * filterEffect)
0098 {
0099     m_effect = dynamic_cast<ConvolveMatrixEffect*>(filterEffect);
0100     if (!m_effect)
0101         return false;
0102 
0103     m_edgeMode->blockSignals(true);
0104     m_edgeMode->setCurrentIndex(m_effect->edgeMode());
0105     m_edgeMode->blockSignals(false);
0106     m_orderX->blockSignals(true);
0107     m_orderX->setValue(m_effect->order().x());
0108     m_orderX->blockSignals(false);
0109     m_orderY->blockSignals(true);
0110     m_orderY->setValue(m_effect->order().y());
0111     m_orderY->blockSignals(false);
0112     m_targetX->blockSignals(true);
0113     m_targetX->setMaximum(m_orderX->value());
0114     m_targetX->setValue(m_effect->target().x()+1);
0115     m_targetX->blockSignals(false);
0116     m_targetY->blockSignals(true);
0117     m_targetY->setMaximum(m_orderY->value());
0118     m_targetY->setValue(m_effect->target().y()+1);
0119     m_targetY->blockSignals(false);
0120     m_divisor->blockSignals(true);
0121     m_divisor->setValue(m_effect->divisor());
0122     m_divisor->blockSignals(false);
0123     m_bias->blockSignals(true);
0124     m_bias->setValue(m_effect->bias());
0125     m_bias->blockSignals(false);
0126     m_preserveAlpha->blockSignals(true);
0127     m_preserveAlpha->setChecked(m_effect->isPreserveAlphaEnabled());
0128     m_preserveAlpha->blockSignals(false);
0129 
0130     return true;
0131 }
0132 
0133 void ConvolveMatrixEffectConfigWidget::edgeModeChanged(int id)
0134 {
0135     if (!m_effect)
0136         return;
0137 
0138     switch(id) {
0139         case ConvolveMatrixEffect::Duplicate:
0140             m_effect->setEdgeMode(ConvolveMatrixEffect::Duplicate);
0141             break;
0142         case ConvolveMatrixEffect::Wrap:
0143             m_effect->setEdgeMode(ConvolveMatrixEffect::Wrap);
0144             break;
0145         case ConvolveMatrixEffect::None:
0146             m_effect->setEdgeMode(ConvolveMatrixEffect::None);
0147             break;
0148     }
0149     emit filterChanged();
0150 }
0151 
0152 void ConvolveMatrixEffectConfigWidget::orderChanged(int)
0153 {
0154     if (!m_effect)
0155         return;
0156 
0157     QPoint newOrder(m_orderX->value(), m_orderY->value());
0158     QPoint oldOrder = m_effect->order();
0159     if (newOrder != oldOrder) {
0160         m_effect->setOrder(newOrder);
0161         const int newSize = newOrder.x() * newOrder.y();
0162         const int oldSize = oldOrder.x() * oldOrder.y();
0163         QVector<qreal> kernel = m_effect->kernel();
0164         if (newSize > oldSize) {
0165             kernel.insert(kernel.end(), newSize-oldSize, 0);
0166         } else {
0167             kernel.resize(newSize);
0168         }
0169         m_effect->setKernel(kernel);
0170         emit filterChanged();
0171     }
0172 
0173     m_targetX->setMaximum(newOrder.x());
0174     m_targetY->setMaximum(newOrder.y());
0175 }
0176 
0177 void ConvolveMatrixEffectConfigWidget::targetChanged(int)
0178 {
0179     if (!m_effect)
0180         return;
0181 
0182     QPoint newTarget(m_targetX->value()-1, m_targetY->value()-1);
0183     QPoint oldTarget = m_effect->target();
0184     if (newTarget != oldTarget) {
0185         m_effect->setTarget(newTarget);
0186         emit filterChanged();
0187     }
0188 }
0189 
0190 void ConvolveMatrixEffectConfigWidget::divisorChanged(double divisor)
0191 {
0192     if (!m_effect)
0193         return;
0194 
0195     if (divisor != m_effect->divisor()) {
0196         m_effect->setDivisor(divisor);
0197         emit filterChanged();
0198     }
0199 }
0200 
0201 void ConvolveMatrixEffectConfigWidget::biasChanged(double bias)
0202 {
0203     if (!m_effect)
0204         return;
0205 
0206     if (bias != m_effect->bias()) {
0207         m_effect->setBias(bias);
0208         emit filterChanged();
0209     }
0210 }
0211 
0212 void ConvolveMatrixEffectConfigWidget::preserveAlphaChanged(bool checked)
0213 {
0214     if (!m_effect)
0215         return;
0216 
0217     m_effect->enablePreserveAlpha(checked);
0218     emit filterChanged();
0219 }
0220 
0221 void ConvolveMatrixEffectConfigWidget::editKernel()
0222 {
0223     if (!m_effect)
0224         return;
0225 
0226     QVector<qreal> oldKernel = m_effect->kernel();
0227     QPoint kernelSize = m_effect->order();
0228     m_matrixModel->setMatrix(oldKernel, kernelSize.y(), kernelSize.x());
0229     connect(m_matrixModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(kernelChanged()));
0230 
0231     QPointer<QDialog> dlg = new QDialog(this);
0232     QTableView * table = new QTableView(dlg);
0233     table->setModel(m_matrixModel);
0234     table->horizontalHeader()->hide();
0235     table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
0236     table->verticalHeader()->hide();
0237     table->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
0238     QVBoxLayout *mainLayout = new QVBoxLayout;
0239     dlg->setLayout(mainLayout);
0240     mainLayout->addWidget(table);
0241     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, dlg);
0242     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0243     okButton->setDefault(true);
0244     okButton->setShortcut(Qt::Key_Return);
0245     mainLayout->addWidget(buttonBox);
0246     connect(buttonBox, SIGNAL(accepted()), dlg, SLOT(accept()));
0247     connect(buttonBox, SIGNAL(rejected()), dlg, SLOT(reject()));
0248     if (dlg->exec() == QDialog::Accepted) {
0249         m_effect->setKernel(m_matrixModel->matrix());
0250         emit filterChanged();
0251     } else {
0252         m_effect->setKernel(oldKernel);
0253     }
0254     delete dlg;
0255 
0256     disconnect(m_matrixModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(kernelChanged()));
0257 }
0258 
0259 void ConvolveMatrixEffectConfigWidget::kernelChanged()
0260 {
0261     if (!m_effect)
0262         return;
0263 
0264     m_effect->setKernel(m_matrixModel->matrix());
0265     emit filterChanged();
0266 }