File indexing completed on 2024-05-12 15:28:16

0001 /***************************************************************************
0002     File                 : DatapickerImageWidget.cpp
0003     Project              : LabPlot
0004     Description          : widget for datapicker properties
0005     --------------------------------------------------------------------
0006     Copyright            : (C) 2015-2016 by Ankit Wagadre (wagadre.ankit@gmail.com)
0007     Copyright            : (C) 2015-2019 by Alexander Semke (alexander.semke@web.de)
0008 
0009  ***************************************************************************/
0010 /***************************************************************************
0011  *                                                                         *
0012  *  This program is free software; you can redistribute it and/or modify   *
0013  *  it under the terms of the GNU General Public License as published by   *
0014  *  the Free Software Foundation; either version 2 of the License, or      *
0015  *  (at your option) any later version.                                    *
0016  *                                                                         *
0017  *  This program is distributed in the hope that it will be useful,        *
0018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0020  *  GNU General Public License for more details.                           *
0021  *                                                                         *
0022  *   You should have received a copy of the GNU General Public License     *
0023  *   along with this program; if not, write to the Free Software           *
0024  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0025  *   Boston, MA  02110-1301  USA                                           *
0026  *                                                                         *
0027  ***************************************************************************/
0028 
0029 #include "DatapickerImageWidget.h"
0030 #include "backend/datapicker/DatapickerPoint.h"
0031 #include "commonfrontend/widgets/qxtspanslider.h"
0032 #include "kdefrontend/GuiTools.h"
0033 #include "backend/worksheet/Worksheet.h"
0034 #include "backend/worksheet/plots/cartesian/Symbol.h"
0035 #include "backend/datapicker/ImageEditor.h"
0036 
0037 #include <QCompleter>
0038 #include <QDir>
0039 #include <QFileDialog>
0040 #include <QDirModel>
0041 #include <QGraphicsScene>
0042 #include <QImageReader>
0043 #include <QPainter>
0044 
0045 #include <KConfigGroup>
0046 #include <KLocalizedString>
0047 #include <KSharedConfig>
0048 
0049 #include <cmath>
0050 
0051 HistogramView::HistogramView(QWidget* parent, int range) : QGraphicsView(parent),
0052     m_scene(new QGraphicsScene()),
0053     m_range(range) {
0054 
0055     setTransform(QTransform());
0056     QRectF pageRect( 0, 0, 1000, 100 );
0057     m_scene->setSceneRect(pageRect);
0058     setScene(m_scene);
0059     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
0060     setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
0061 
0062     m_lowerSlider = new QGraphicsRectItem(pageRect, nullptr);
0063     m_lowerSlider->setPen(QPen(Qt::black, 0.5));
0064     m_lowerSlider->setBrush(Qt::blue);
0065     m_lowerSlider->setOpacity(0.2);
0066     m_scene->addItem(m_lowerSlider);
0067 
0068     m_upperSlider = new QGraphicsRectItem(pageRect, nullptr);
0069     m_upperSlider->setPen(QPen(Qt::black, 0.5));
0070     m_upperSlider->setBrush(Qt::blue);
0071     m_upperSlider->setOpacity(0.2);
0072     m_scene->addItem(m_upperSlider);
0073 }
0074 
0075 void HistogramView::setScalePixmap(const QString& file) {
0076     // scene rect is 1000*100 where upper 1000*80 is for histogram graph
0077     // and lower 1000*20 is for histogram scale
0078     auto* pixmap = new QGraphicsPixmapItem(QPixmap(file).scaled( 1000, 20, Qt::IgnoreAspectRatio), nullptr);
0079     pixmap->setZValue(-1);
0080     pixmap->setPos(0, 90);
0081     m_scene->addItem(pixmap);
0082 }
0083 
0084 void HistogramView::setSpan(int l, int h) {
0085     l = l*1000/m_range;
0086     h = h*1000/m_range;
0087     m_lowerSlider->setPos(QPointF(l - 1000, 0));
0088     m_upperSlider->setPos(QPointF(h, 0));
0089     invalidateScene(sceneRect(), QGraphicsScene::BackgroundLayer);
0090 }
0091 
0092 void HistogramView::resizeEvent(QResizeEvent *event) {
0093     fitInView(m_scene->sceneRect(), Qt::IgnoreAspectRatio);
0094     QGraphicsView::resizeEvent(event);
0095 }
0096 
0097 void HistogramView::drawBackground(QPainter* painter, const QRectF& rect) {
0098     if (!bins)
0099         return;
0100 
0101     painter->save();
0102     painter->setRenderHint(QPainter::Antialiasing, true);
0103     int max = 1;
0104     for (int i = 0; i <= m_range; i++)
0105         if (bins [i] > max)
0106             max = bins [i];
0107 
0108     // convert y-scale count to log scale so small counts are still visible
0109     // scene rect is 1000*100 where upper 1000*80 is for histogram graph
0110     // and lower 1000*20 is for histogram scale
0111     QPainterPath path(QPointF(0, (log(bins[0])*100/log(max))));
0112     for (int i = 1; i <= m_range; i++) {
0113         int x = i*1000/m_range;
0114         int y = 80;
0115         if ( bins[i] > 1 )
0116             y = 80 - (log(bins[i])*80/log(max));
0117 
0118         path.lineTo(QPointF(x, y));
0119     }
0120 
0121     painter->drawPath(path);
0122     invalidateScene(rect, QGraphicsScene::BackgroundLayer);
0123     painter->restore();
0124 }
0125 
0126 DatapickerImageWidget::DatapickerImageWidget(QWidget* parent) : BaseDock(parent), m_image(nullptr) {
0127     ui.setupUi(this);
0128     m_leName = ui.leName;
0129     m_leComment = ui.leComment;
0130 
0131     ui.leFileName->setClearButtonEnabled(true);
0132     ui.bOpen->setIcon( QIcon::fromTheme("document-open") );
0133     ui.leFileName->setCompleter(new QCompleter(new QDirModel, this));
0134 
0135     auto* editTabLayout = static_cast<QGridLayout*>(ui.tEdit->layout());
0136     editTabLayout->setContentsMargins(2,2,2,2);
0137     editTabLayout->setHorizontalSpacing(2);
0138     editTabLayout->setVerticalSpacing(4);
0139 
0140     ssHue = new QxtSpanSlider(Qt::Horizontal, ui.tEdit);
0141     ssHue->setToolTip(i18n("Select the range for the hue.\nEverything outside of this range will be set to white."));
0142     ssHue->setRange(0, 360);
0143     editTabLayout->addWidget(ssHue, 3, 2);
0144 
0145     ssSaturation = new QxtSpanSlider(Qt::Horizontal, ui.tEdit);
0146     ssSaturation->setToolTip(i18n("Select the range for the saturation.\nEverything outside of this range will be set to white."));
0147     ssSaturation->setRange(0,100);
0148     editTabLayout->addWidget(ssSaturation, 5, 2);
0149 
0150     ssValue = new QxtSpanSlider(Qt::Horizontal, ui.tEdit);
0151     ssValue->setToolTip(i18n("Select the range for the value, the degree of lightness of the color.\nEverything outside of this range will be set to white."));
0152     ssValue->setRange(0,100);
0153     editTabLayout->addWidget(ssValue, 7, 2);
0154 
0155     ssIntensity = new QxtSpanSlider(Qt::Horizontal, ui.tEdit);
0156     ssIntensity->setToolTip(i18n("Select the range for the intensity.\nEverything outside of this range will be set to white."));
0157     ssIntensity->setRange(0, 100);
0158     editTabLayout->addWidget(ssIntensity, 9, 2);
0159 
0160     ssForeground = new QxtSpanSlider(Qt::Horizontal, ui.tEdit);
0161     ssForeground->setToolTip(i18n("Select the range for the colors that are not part of the background color.\nEverything outside of this range will be set to white."));
0162     ssForeground->setRange(0, 100);
0163     editTabLayout->addWidget(ssForeground, 11, 2);
0164 
0165     ui.cbGraphType->addItem(i18n("Cartesian (x, y)"));
0166     ui.cbGraphType->addItem(i18n("Polar (x, y°)"));
0167     ui.cbGraphType->addItem(i18n("Polar (x, y(rad))"));
0168     ui.cbGraphType->addItem(i18n("Logarithmic (ln(x), y)"));
0169     ui.cbGraphType->addItem(i18n("Logarithmic (x, ln(y))"));
0170     ui.cbGraphType->addItem(i18n("Ternary (x, y, z)"));
0171 
0172     ui.lTernaryScale->setHidden(true);
0173     ui.sbTernaryScale->setHidden(true);
0174     ui.lPositionZ1->setHidden(true);
0175     ui.lPositionZ2->setHidden(true);
0176     ui.lPositionZ3->setHidden(true);
0177     ui.sbPositionZ1->setHidden(true);
0178     ui.sbPositionZ2->setHidden(true);
0179     ui.sbPositionZ3->setHidden(true);
0180 
0181     ui.cbPlotImageType->addItem(i18n("No Image"));
0182     ui.cbPlotImageType->addItem(i18n("Original Image"));
0183     ui.cbPlotImageType->addItem(i18n("Processed Image"));
0184 
0185     QString valueFile = QStandardPaths::locate(QStandardPaths::AppDataLocation, "pics/colorchooser/colorchooser_value.xpm");
0186     QString hueFile = QStandardPaths::locate(QStandardPaths::AppDataLocation, "pics/colorchooser/colorchooser_hue.xpm");
0187     QString saturationFile = QStandardPaths::locate(QStandardPaths::AppDataLocation, "pics/colorchooser/colorchooser_saturation.xpm");
0188 
0189     gvHue = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::ColorAttributes::Hue));
0190     gvHue->setToolTip(i18n("Select the range for the hue.\nEverything outside of this range will be set to white."));
0191     editTabLayout->addWidget(gvHue, 2, 2);
0192     gvHue->setScalePixmap(hueFile);
0193 
0194     gvSaturation = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::ColorAttributes::Saturation));
0195     gvSaturation->setToolTip(i18n("Select the range for the saturation.\nEverything outside of this range will be set to white."));
0196     editTabLayout->addWidget(gvSaturation, 4, 2);
0197     gvSaturation->setScalePixmap(saturationFile);
0198 
0199     gvValue = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::ColorAttributes::Value));
0200     gvValue->setToolTip(i18n("Select the range for the value, the degree of lightness of the color.\nEverything outside of this range will be set to white."));
0201     editTabLayout->addWidget(gvValue, 6,2);
0202     gvValue->setScalePixmap(valueFile);
0203 
0204     gvIntensity = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::ColorAttributes::Intensity));
0205     gvIntensity->setToolTip(i18n("Select the range for the intensity.\nEverything outside of this range will be set to white."));
0206     editTabLayout->addWidget(gvIntensity, 8, 2);
0207     gvIntensity->setScalePixmap(valueFile);
0208 
0209     gvForeground = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::ColorAttributes::Foreground));
0210     gvForeground->setToolTip(i18n("Select the range for the colors that are not part of the background color.\nEverything outside of this range will be set to white."));
0211     editTabLayout->addWidget(gvForeground, 10, 2);
0212     gvForeground->setScalePixmap(valueFile);
0213 
0214     DatapickerImageWidget::updateLocale();
0215 
0216     //SLOTS
0217     //general
0218     connect(ui.leName, &QLineEdit::textChanged, this, &DatapickerImageWidget::nameChanged);
0219     connect(ui.leComment, &QLineEdit::textChanged, this, &DatapickerImageWidget::commentChanged);
0220     connect(ui.bOpen, &QPushButton::clicked, this, &DatapickerImageWidget::selectFile);
0221     connect(ui.leFileName, &QLineEdit::returnPressed, this, &DatapickerImageWidget::fileNameChanged);
0222     connect(ui.leFileName, &QLineEdit::textChanged, this, &DatapickerImageWidget::fileNameChanged);
0223 
0224     // edit image
0225     connect(ui.cbPlotImageType, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
0226             this, &DatapickerImageWidget::plotImageTypeChanged);
0227     connect(ui.sbRotation, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
0228             this, &DatapickerImageWidget::rotationChanged);
0229     connect(ssIntensity, &QxtSpanSlider::spanChanged, this, &DatapickerImageWidget::intensitySpanChanged);
0230     connect(ssIntensity, &QxtSpanSlider::spanChanged, gvIntensity, &HistogramView::setSpan);
0231     connect(ssForeground, &QxtSpanSlider::spanChanged, this, &DatapickerImageWidget::foregroundSpanChanged);
0232     connect(ssForeground, &QxtSpanSlider::spanChanged, gvForeground, &HistogramView::setSpan );
0233     connect(ssHue, &QxtSpanSlider::spanChanged, this, &DatapickerImageWidget::hueSpanChanged);
0234     connect(ssHue, &QxtSpanSlider::spanChanged, gvHue, &HistogramView::setSpan );
0235     connect(ssSaturation, &QxtSpanSlider::spanChanged, this, &DatapickerImageWidget::saturationSpanChanged);
0236     connect(ssSaturation, &QxtSpanSlider::spanChanged, gvSaturation, &HistogramView::setSpan );
0237     connect(ssValue, &QxtSpanSlider::spanChanged, this, &DatapickerImageWidget::valueSpanChanged);
0238     connect(ssValue, &QxtSpanSlider::spanChanged, gvValue, &HistogramView::setSpan );
0239     connect(ui.sbMinSegmentLength, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
0240             this, &DatapickerImageWidget::minSegmentLengthChanged);
0241     connect(ui.sbPointSeparation, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
0242             this, &DatapickerImageWidget::pointSeparationChanged);
0243 
0244     //axis point
0245     connect(ui.cbGraphType, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
0246             this, &DatapickerImageWidget::graphTypeChanged);
0247     connect(ui.sbTernaryScale, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
0248             this, &DatapickerImageWidget::ternaryScaleChanged);
0249     connect(ui.sbPositionX1, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
0250             this, &DatapickerImageWidget::logicalPositionChanged);
0251     connect(ui.sbPositionY1, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
0252             this, &DatapickerImageWidget::logicalPositionChanged);
0253     connect(ui.sbPositionX2, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
0254             this, &DatapickerImageWidget::logicalPositionChanged);
0255     connect(ui.sbPositionY2, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
0256             this, &DatapickerImageWidget::logicalPositionChanged);
0257     connect(ui.sbPositionX3, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
0258             this, &DatapickerImageWidget::logicalPositionChanged);
0259     connect(ui.sbPositionY3, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
0260             this, &DatapickerImageWidget::logicalPositionChanged);
0261     connect(ui.sbPositionZ1, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
0262             this, &DatapickerImageWidget::logicalPositionChanged);
0263     connect(ui.sbPositionZ2, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
0264             this, &DatapickerImageWidget::logicalPositionChanged);
0265     connect(ui.sbPositionZ3, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
0266             this, &DatapickerImageWidget::logicalPositionChanged);
0267 
0268     //SYMBOL
0269     connect(ui.cbSymbolStyle, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
0270             this, &DatapickerImageWidget::pointsStyleChanged);
0271     connect(ui.sbSymbolSize, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
0272             this, &DatapickerImageWidget::pointsSizeChanged);
0273     connect(ui.sbSymbolRotation,static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
0274             this, &DatapickerImageWidget::pointsRotationChanged);
0275     connect(ui.sbSymbolOpacity, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
0276             this, &DatapickerImageWidget::pointsOpacityChanged);
0277 
0278     //Filling
0279     connect(ui.cbSymbolFillingStyle, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
0280             this, &DatapickerImageWidget::pointsFillingStyleChanged);
0281     connect(ui.kcbSymbolFillingColor, &KColorButton::changed, this, &DatapickerImageWidget::pointsFillingColorChanged);
0282 
0283     //border
0284     connect(ui.cbSymbolBorderStyle, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
0285             this, &DatapickerImageWidget::pointsBorderStyleChanged);
0286     connect(ui.kcbSymbolBorderColor, &KColorButton::changed, this, &DatapickerImageWidget::pointsBorderColorChanged);
0287     connect(ui.sbSymbolBorderWidth, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
0288             this, &DatapickerImageWidget::pointsBorderWidthChanged);
0289 
0290     connect(ui.chbSymbolVisible, &QCheckBox::clicked, this, &DatapickerImageWidget::pointsVisibilityChanged);
0291 
0292     init();
0293 }
0294 
0295 void DatapickerImageWidget::init() {
0296     m_initializing = true;
0297     GuiTools::updatePenStyles(ui.cbSymbolBorderStyle, Qt::black);
0298 
0299     QPainter pa;
0300     int iconSize = 20;
0301     QPixmap pm(iconSize, iconSize);
0302     QPen pen(Qt::SolidPattern, 0);
0303     ui.cbSymbolStyle->setIconSize(QSize(iconSize, iconSize));
0304     QTransform trafo;
0305     trafo.scale(15, 15);
0306     //TODO: constant?
0307     for (int i = 1; i < 19; ++i) {
0308         auto style = (Symbol::Style)i;
0309         pm.fill(Qt::transparent);
0310         pa.begin(&pm);
0311         pa.setPen( pen );
0312         pa.setRenderHint(QPainter::Antialiasing);
0313         pa.translate(iconSize/2,iconSize/2);
0314         pa.drawPath(trafo.map(Symbol::pathFromStyle(style)));
0315         pa.end();
0316         ui.cbSymbolStyle->addItem(QIcon(pm), Symbol::nameFromStyle(style));
0317     }
0318     GuiTools::updateBrushStyles(ui.cbSymbolFillingStyle, Qt::black);
0319     m_initializing = false;
0320 }
0321 
0322 void DatapickerImageWidget::setImages(QList<DatapickerImage*> list) {
0323     m_initializing = true;
0324     m_imagesList = list;
0325     m_image = list.first();
0326     m_aspect = list.first()->parentAspect();
0327 
0328     if (list.size() == 1) {
0329         ui.lName->setEnabled(true);
0330         ui.leName->setEnabled(true);
0331         ui.lComment->setEnabled(true);
0332         ui.leComment->setEnabled(true);
0333         ui.leName->setText(m_image->parentAspect()->name());
0334         ui.leComment->setText(m_image->parentAspect()->comment());
0335     } else {
0336         ui.lName->setEnabled(false);
0337         ui.leName->setEnabled(false);
0338         ui.lComment->setEnabled(false);
0339         ui.leComment->setEnabled(false);
0340         ui.leName->setText(QString());
0341         ui.leComment->setText(QString());
0342     }
0343 
0344     this->load();
0345     initConnections();
0346     handleWidgetActions();
0347     updateSymbolWidgets();
0348     m_initializing = false;
0349 }
0350 
0351 void DatapickerImageWidget::initConnections() {
0352     connect(m_image->parentAspect(), &AbstractAspect::aspectDescriptionChanged, this, &DatapickerImageWidget::imageDescriptionChanged);
0353     connect(m_image, &DatapickerImage::fileNameChanged, this, &DatapickerImageWidget::imageFileNameChanged);
0354     connect(m_image, &DatapickerImage::rotationAngleChanged, this, &DatapickerImageWidget::imageRotationAngleChanged);
0355     connect(m_image, &AbstractAspect::aspectRemoved, this, &DatapickerImageWidget::updateSymbolWidgets);
0356     connect(m_image, &AbstractAspect::aspectAdded, this, &DatapickerImageWidget::updateSymbolWidgets);
0357     connect(m_image, &DatapickerImage::axisPointsChanged, this, &DatapickerImageWidget::imageAxisPointsChanged);
0358     connect(m_image, &DatapickerImage::settingsChanged, this, &DatapickerImageWidget::imageEditorSettingsChanged);
0359     connect(m_image, &DatapickerImage::minSegmentLengthChanged, this, &DatapickerImageWidget::imageMinSegmentLengthChanged);
0360     connect(m_image, &DatapickerImage::pointStyleChanged, this, &DatapickerImageWidget::symbolStyleChanged);
0361     connect(m_image, &DatapickerImage::pointSizeChanged, this, &DatapickerImageWidget::symbolSizeChanged);
0362     connect(m_image, &DatapickerImage::pointRotationAngleChanged, this, &DatapickerImageWidget::symbolRotationAngleChanged);
0363     connect(m_image, &DatapickerImage::pointOpacityChanged, this, &DatapickerImageWidget::symbolOpacityChanged);
0364     connect(m_image, &DatapickerImage::pointBrushChanged, this, &DatapickerImageWidget::symbolBrushChanged);
0365     connect(m_image, &DatapickerImage::pointPenChanged, this, &DatapickerImageWidget::symbolPenChanged);
0366     connect(m_image, &DatapickerImage::pointVisibilityChanged, this, &DatapickerImageWidget::symbolVisibleChanged);
0367 }
0368 
0369 void DatapickerImageWidget::handleWidgetActions() {
0370     QString fileName =  ui.leFileName->text().trimmed();
0371     bool b = !fileName.isEmpty();
0372     ui.tEdit->setEnabled(b);
0373     ui.cbGraphType->setEnabled(b);
0374     ui.sbRotation->setEnabled(b);
0375     ui.sbPositionX1->setEnabled(b);
0376     ui.sbPositionX2->setEnabled(b);
0377     ui.sbPositionX3->setEnabled(b);
0378     ui.sbPositionY1->setEnabled(b);
0379     ui.sbPositionY2->setEnabled(b);
0380     ui.sbPositionY3->setEnabled(b);
0381     ui.sbMinSegmentLength->setEnabled(b);
0382     ui.sbPointSeparation->setEnabled(b);
0383 
0384     if (b) {
0385         //upload histogram to view
0386         gvIntensity->bins = m_image->intensityBins;
0387         gvForeground->bins = m_image->foregroundBins;
0388         gvHue->bins = m_image->hueBins;
0389         gvSaturation->bins = m_image->saturationBins;
0390         gvValue->bins = m_image->valueBins;
0391     }
0392 }
0393 
0394 void DatapickerImageWidget::updateLocale() {
0395     SET_NUMBER_LOCALE
0396     ui.sbRotation->setLocale(numberLocale);
0397     ui.sbPositionX1->setLocale(numberLocale);
0398     ui.sbPositionX2->setLocale(numberLocale);
0399     ui.sbPositionX3->setLocale(numberLocale);
0400     ui.sbPositionY1->setLocale(numberLocale);
0401     ui.sbPositionY2->setLocale(numberLocale);
0402     ui.sbPositionY3->setLocale(numberLocale);
0403     ui.sbSymbolSize->setLocale(numberLocale);
0404     ui.sbSymbolBorderWidth->setLocale(numberLocale);
0405 }
0406 
0407 //**********************************************************
0408 //****** SLOTs for changes triggered in DatapickerImageWidget ********
0409 //**********************************************************
0410 //"General"-tab
0411 void DatapickerImageWidget::selectFile() {
0412     KConfigGroup conf(KSharedConfig::openConfig(), "DatapickerImageWidget");
0413     QString dir = conf.readEntry("LastImageDir", "");
0414     QString formats;
0415     for (const QByteArray& format : QImageReader::supportedImageFormats()) {
0416         QString f = "*." + QString(format.constData());
0417         if (f == QLatin1String("*.svg"))
0418             continue;
0419         formats.isEmpty() ? formats += f : formats += " " + f;
0420     }
0421     QString path = QFileDialog::getOpenFileName(this, i18n("Select the image file"), dir, i18n("Images (%1)", formats));
0422     if (path.isEmpty())
0423         return; //cancel was clicked in the file-dialog
0424 
0425     int pos = path.lastIndexOf(QLatin1String("/"));
0426     if (pos != -1) {
0427         QString newDir = path.left(pos);
0428         if (newDir != dir)
0429             conf.writeEntry("LastImageDir", newDir);
0430     }
0431 
0432     ui.leFileName->setText( path );
0433     handleWidgetActions();
0434 
0435     for (auto* image : m_imagesList)
0436         image->setFileName(path);
0437 }
0438 
0439 void DatapickerImageWidget::fileNameChanged() {
0440     if (m_initializing)
0441         return;
0442 
0443     handleWidgetActions();
0444 
0445     const QString& fileName = ui.leFileName->text();
0446     bool invalid = (!fileName.isEmpty() && !QFile::exists(fileName));
0447     GuiTools::highlight(ui.leFileName, invalid);
0448 
0449     for (auto* image : m_imagesList)
0450         image->setFileName(fileName);
0451 }
0452 
0453 void DatapickerImageWidget::graphTypeChanged() {
0454     if (m_initializing)
0455         return;
0456 
0457     DatapickerImage::ReferencePoints points = m_image->axisPoints();
0458     points.type = DatapickerImage::GraphType(ui.cbGraphType->currentIndex());
0459 
0460     if (points.type != DatapickerImage::GraphType::Ternary) {
0461         ui.lTernaryScale->setHidden(true);
0462         ui.sbTernaryScale->setHidden(true);
0463         ui.lPositionZ1->setHidden(true);
0464         ui.lPositionZ2->setHidden(true);
0465         ui.lPositionZ3->setHidden(true);
0466         ui.sbPositionZ1->setHidden(true);
0467         ui.sbPositionZ2->setHidden(true);
0468         ui.sbPositionZ3->setHidden(true);
0469     } else {
0470         ui.lTernaryScale->setHidden(false);
0471         ui.sbTernaryScale->setHidden(false);
0472         ui.lPositionZ1->setHidden(false);
0473         ui.lPositionZ2->setHidden(false);
0474         ui.lPositionZ3->setHidden(false);
0475         ui.sbPositionZ1->setHidden(false);
0476         ui.sbPositionZ2->setHidden(false);
0477         ui.sbPositionZ3->setHidden(false);
0478     }
0479 
0480     for (auto* image : m_imagesList)
0481         image->setAxisPoints(points);
0482 }
0483 
0484 void DatapickerImageWidget::ternaryScaleChanged(double value) {
0485     if (m_initializing)
0486         return;
0487 
0488     DatapickerImage::ReferencePoints points = m_image->axisPoints();
0489     points.ternaryScale = value;
0490 
0491     for (auto* image : m_imagesList)
0492         image->setAxisPoints(points);
0493 }
0494 
0495 void DatapickerImageWidget::logicalPositionChanged() {
0496     if (m_initializing)
0497         return;
0498 
0499     DatapickerImage::ReferencePoints points = m_image->axisPoints();
0500     points.logicalPos[0].setX(ui.sbPositionX1->value());
0501     points.logicalPos[0].setY(ui.sbPositionY1->value());
0502     points.logicalPos[1].setX(ui.sbPositionX2->value());
0503     points.logicalPos[1].setY(ui.sbPositionY2->value());
0504     points.logicalPos[2].setX(ui.sbPositionX3->value());
0505     points.logicalPos[2].setY(ui.sbPositionY3->value());
0506     points.logicalPos[0].setZ(ui.sbPositionZ1->value());
0507     points.logicalPos[1].setZ(ui.sbPositionZ2->value());
0508     points.logicalPos[2].setZ(ui.sbPositionZ3->value());
0509 
0510     const Lock lock(m_initializing);
0511     for (auto* image : m_imagesList)
0512         image->setAxisPoints(points);
0513 }
0514 
0515 void DatapickerImageWidget::pointsStyleChanged(int index) {
0516     auto style = Symbol::Style(index + 1);
0517     //enable/disable the  filling options in the GUI depending on the currently selected points.
0518     if (style != Symbol::Style::Line && style != Symbol::Style::Cross) {
0519         ui.cbSymbolFillingStyle->setEnabled(true);
0520         bool noBrush = (Qt::BrushStyle(ui.cbSymbolFillingStyle->currentIndex()) == Qt::NoBrush);
0521         ui.kcbSymbolFillingColor->setEnabled(!noBrush);
0522     } else {
0523         ui.kcbSymbolFillingColor->setEnabled(false);
0524         ui.cbSymbolFillingStyle->setEnabled(false);
0525     }
0526 
0527     bool noLine = (Qt::PenStyle(ui.cbSymbolBorderStyle->currentIndex()) == Qt::NoPen);
0528     ui.kcbSymbolBorderColor->setEnabled(!noLine);
0529     ui.sbSymbolBorderWidth->setEnabled(!noLine);
0530 
0531     if (m_initializing)
0532         return;
0533 
0534     for (auto* image : m_imagesList)
0535         image->setPointStyle(style);
0536 }
0537 
0538 void DatapickerImageWidget::pointsSizeChanged(double value) {
0539     if (m_initializing)
0540         return;
0541 
0542     for (auto* image : m_imagesList)
0543         image->setPointSize( Worksheet::convertToSceneUnits(value, Worksheet::Unit::Point) );
0544 }
0545 
0546 void DatapickerImageWidget::pointsRotationChanged(int value) {
0547     if (m_initializing)
0548         return;
0549 
0550     for (auto* image : m_imagesList)
0551         image->setPointRotationAngle(value);
0552 }
0553 
0554 void DatapickerImageWidget::pointsOpacityChanged(int value) {
0555     if (m_initializing)
0556         return;
0557 
0558     qreal opacity = (float)value/100.;
0559     for (auto* image : m_imagesList)
0560         image->setPointOpacity(opacity);
0561 }
0562 
0563 void DatapickerImageWidget::pointsFillingStyleChanged(int index) {
0564     auto brushStyle = Qt::BrushStyle(index);
0565     ui.kcbSymbolFillingColor->setEnabled(!(brushStyle == Qt::NoBrush));
0566 
0567     if (m_initializing)
0568         return;
0569 
0570     QBrush brush;
0571     for (auto* image : m_imagesList) {
0572         brush = image->pointBrush();
0573         brush.setStyle(brushStyle);
0574         image->setPointBrush(brush);
0575     }
0576 }
0577 
0578 void DatapickerImageWidget::pointsFillingColorChanged(const QColor& color) {
0579     if (m_initializing)
0580         return;
0581 
0582     QBrush brush;
0583     for (auto* image : m_imagesList) {
0584         brush = image->pointBrush();
0585         brush.setColor(color);
0586         image->setPointBrush(brush);
0587     }
0588 
0589     m_initializing = true;
0590     GuiTools::updateBrushStyles(ui.cbSymbolFillingStyle, color );
0591     m_initializing = false;
0592 }
0593 
0594 void DatapickerImageWidget::pointsBorderStyleChanged(int index) {
0595     auto penStyle = Qt::PenStyle(index);
0596 
0597     if ( penStyle == Qt::NoPen ) {
0598         ui.kcbSymbolBorderColor->setEnabled(false);
0599         ui.sbSymbolBorderWidth->setEnabled(false);
0600     } else {
0601         ui.kcbSymbolBorderColor->setEnabled(true);
0602         ui.sbSymbolBorderWidth->setEnabled(true);
0603     }
0604 
0605     if (m_initializing)
0606         return;
0607 
0608     QPen pen;
0609     for (auto* image : m_imagesList) {
0610         pen = image->pointPen();
0611         pen.setStyle(penStyle);
0612         image->setPointPen(pen);
0613     }
0614 }
0615 
0616 void DatapickerImageWidget::pointsBorderColorChanged(const QColor& color) {
0617     if (m_initializing)
0618         return;
0619 
0620     QPen pen;
0621     for (auto* image : m_imagesList) {
0622         pen = image->pointPen();
0623         pen.setColor(color);
0624         image->setPointPen(pen);
0625     }
0626 
0627     m_initializing = true;
0628     GuiTools::updatePenStyles(ui.cbSymbolBorderStyle, color);
0629     m_initializing = false;
0630 }
0631 
0632 void DatapickerImageWidget::pointsBorderWidthChanged(double value) {
0633     if (m_initializing)
0634         return;
0635 
0636     QPen pen;
0637     for (auto* image : m_imagesList) {
0638         pen = image->pointPen();
0639         pen.setWidthF( Worksheet::convertToSceneUnits(value, Worksheet::Unit::Point) );
0640         image->setPointPen(pen);
0641     }
0642 }
0643 
0644 void DatapickerImageWidget::pointsVisibilityChanged(bool state) {
0645     if (m_initializing)
0646         return;
0647 
0648     for (auto* image : m_imagesList)
0649         image->setPointVisibility(state);
0650 }
0651 
0652 void DatapickerImageWidget::intensitySpanChanged(int lowerLimit, int upperLimit) {
0653     if (m_initializing)
0654         return;
0655 
0656     DatapickerImage::EditorSettings settings = m_image->settings();
0657     settings.intensityThresholdHigh = upperLimit;
0658     settings.intensityThresholdLow = lowerLimit;
0659     for (auto* image : m_imagesList)
0660         image->setSettings(settings);
0661 }
0662 
0663 void DatapickerImageWidget::foregroundSpanChanged(int lowerLimit, int upperLimit) {
0664     if (m_initializing)
0665         return;
0666 
0667     DatapickerImage::EditorSettings settings = m_image->settings();
0668     settings.foregroundThresholdHigh = upperLimit;
0669     settings.foregroundThresholdLow = lowerLimit;
0670     for (auto* image : m_imagesList)
0671         image->setSettings(settings);
0672 }
0673 
0674 void DatapickerImageWidget::hueSpanChanged(int lowerLimit, int upperLimit) {
0675     if (m_initializing)
0676         return;
0677 
0678     DatapickerImage::EditorSettings settings = m_image->settings();
0679     settings.hueThresholdHigh = upperLimit;
0680     settings.hueThresholdLow = lowerLimit;
0681     for (auto* image : m_imagesList)
0682         image->setSettings(settings);
0683 }
0684 
0685 void DatapickerImageWidget::saturationSpanChanged(int lowerLimit, int upperLimit) {
0686     if (m_initializing)
0687         return;
0688 
0689     DatapickerImage::EditorSettings settings = m_image->settings();
0690     settings.saturationThresholdHigh = upperLimit;
0691     settings.saturationThresholdLow = lowerLimit;
0692     for (auto* image : m_imagesList)
0693         image->setSettings(settings);
0694 }
0695 
0696 void DatapickerImageWidget::valueSpanChanged(int lowerLimit, int upperLimit) {
0697     if (m_initializing)
0698         return;
0699 
0700     DatapickerImage::EditorSettings settings = m_image->settings();
0701     settings.valueThresholdHigh = upperLimit;
0702     settings.valueThresholdLow = lowerLimit;
0703     for (auto* image : m_imagesList)
0704         image->setSettings(settings);
0705 }
0706 
0707 void DatapickerImageWidget::plotImageTypeChanged(int index) {
0708     if (m_initializing)
0709         return;
0710 
0711     for (auto* image : m_imagesList)
0712         image->setPlotImageType(DatapickerImage::PlotImageType(index));
0713 }
0714 
0715 void DatapickerImageWidget::rotationChanged(double value) {
0716     if (m_initializing)
0717         return;
0718 
0719     for (auto* image : m_imagesList)
0720         image->setRotationAngle(value);
0721 }
0722 
0723 void DatapickerImageWidget::minSegmentLengthChanged(int value) {
0724     if (m_initializing)
0725         return;
0726 
0727     for (auto* image : m_imagesList)
0728         image->setminSegmentLength(value);
0729 }
0730 
0731 void DatapickerImageWidget::pointSeparationChanged(int value) {
0732     if (m_initializing)
0733         return;
0734 
0735     for (auto* image : m_imagesList)
0736         image->setPointSeparation(value);
0737 }
0738 
0739 //*******************************************************************
0740 //******** SLOTs for changes triggered in DatapickerImage ***********
0741 //*******************************************************************
0742 /*!
0743  * called when the name or comment of image's parent (datapicker) was changed.
0744  */
0745 void DatapickerImageWidget::imageDescriptionChanged(const AbstractAspect* aspect) {
0746     if (m_image->parentAspect() != aspect)
0747         return;
0748 
0749     m_initializing = true;
0750     if (aspect->name() != ui.leName->text()) {
0751         ui.leName->setText(aspect->name());
0752     } else if (aspect->comment() != ui.leComment->text()) {
0753         ui.leComment->setText(aspect->comment());
0754     }
0755     m_initializing = false;
0756 }
0757 
0758 void DatapickerImageWidget::imageFileNameChanged(const QString& name) {
0759     m_initializing = true;
0760     ui.leFileName->setText(name);
0761     m_initializing = false;
0762 }
0763 
0764 void DatapickerImageWidget::imageRotationAngleChanged(float angle) {
0765     m_initializing = true;
0766     ui.sbRotation->setValue(angle);
0767     m_initializing = false;
0768 }
0769 
0770 void DatapickerImageWidget::imageAxisPointsChanged(const DatapickerImage::ReferencePoints& axisPoints) {
0771     if (m_initializing)return;
0772     const Lock lock(m_initializing);
0773     m_initializing = true;
0774     ui.cbGraphType->setCurrentIndex((int) axisPoints.type);
0775     ui.sbTernaryScale->setValue(axisPoints.ternaryScale);
0776     ui.sbPositionX1->setValue(axisPoints.logicalPos[0].x());
0777     ui.sbPositionY1->setValue(axisPoints.logicalPos[0].y());
0778     ui.sbPositionX2->setValue(axisPoints.logicalPos[1].x());
0779     ui.sbPositionY2->setValue(axisPoints.logicalPos[1].y());
0780     ui.sbPositionX3->setValue(axisPoints.logicalPos[2].x());
0781     ui.sbPositionY3->setValue(axisPoints.logicalPos[2].y());
0782     ui.sbPositionZ1->setValue(axisPoints.logicalPos[0].z());
0783     ui.sbPositionZ2->setValue(axisPoints.logicalPos[1].z());
0784     ui.sbPositionZ3->setValue(axisPoints.logicalPos[2].z());
0785     m_initializing = false;
0786 }
0787 
0788 void DatapickerImageWidget::imageEditorSettingsChanged(const DatapickerImage::EditorSettings& settings) {
0789     m_initializing = true;
0790     ssIntensity->setSpan(settings.intensityThresholdLow, settings.intensityThresholdHigh);
0791     ssForeground->setSpan(settings.foregroundThresholdLow, settings.foregroundThresholdHigh);
0792     ssHue->setSpan(settings.hueThresholdLow, settings.hueThresholdHigh);
0793     ssSaturation->setSpan(settings.saturationThresholdLow, settings.saturationThresholdHigh);
0794     ssValue->setSpan(settings.valueThresholdLow, settings.valueThresholdHigh);
0795     gvIntensity->setSpan(settings.intensityThresholdLow, settings.intensityThresholdHigh);
0796     gvForeground->setSpan(settings.foregroundThresholdLow, settings.foregroundThresholdHigh);
0797     gvHue->setSpan(settings.hueThresholdLow, settings.hueThresholdHigh);
0798     gvSaturation->setSpan(settings.saturationThresholdLow, settings.saturationThresholdHigh);
0799     gvValue->setSpan(settings.valueThresholdLow, settings.valueThresholdHigh);
0800     m_initializing = false;
0801 }
0802 
0803 void DatapickerImageWidget::imageMinSegmentLengthChanged(const int value) {
0804     m_initializing = true;
0805     ui.sbMinSegmentLength->setValue(value);
0806     m_initializing = false;
0807 }
0808 
0809 void DatapickerImageWidget::updateSymbolWidgets() {
0810     int pointCount = m_image->childCount<DatapickerPoint>(AbstractAspect::ChildIndexFlag::IncludeHidden);
0811     if (pointCount)
0812         ui.tSymbol->setEnabled(true);
0813     else
0814         ui.tSymbol->setEnabled(false);
0815 }
0816 
0817 void DatapickerImageWidget::symbolStyleChanged(Symbol::Style style) {
0818     m_initializing = true;
0819     ui.cbSymbolStyle->setCurrentIndex((int)style - 1);
0820     m_initializing = false;
0821 }
0822 
0823 void DatapickerImageWidget::symbolSizeChanged(qreal size) {
0824     m_initializing = true;
0825     ui.sbSymbolSize->setValue( Worksheet::convertFromSceneUnits(size, Worksheet::Unit::Point) );
0826     m_initializing = false;
0827 }
0828 
0829 void DatapickerImageWidget::symbolRotationAngleChanged(qreal angle) {
0830     m_initializing = true;
0831     ui.sbSymbolRotation->setValue(round(angle));
0832     m_initializing = false;
0833 }
0834 
0835 void DatapickerImageWidget::symbolOpacityChanged(qreal opacity) {
0836     m_initializing = true;
0837     ui.sbSymbolOpacity->setValue( round(opacity*100.0) );
0838     m_initializing = false;
0839 }
0840 
0841 void DatapickerImageWidget::symbolBrushChanged(const QBrush& brush) {
0842     m_initializing = true;
0843     ui.cbSymbolFillingStyle->setCurrentIndex((int) brush.style());
0844     ui.kcbSymbolFillingColor->setColor(brush.color());
0845     GuiTools::updateBrushStyles(ui.cbSymbolFillingStyle, brush.color());
0846     m_initializing = false;
0847 }
0848 
0849 void DatapickerImageWidget::symbolPenChanged(const QPen& pen) {
0850     m_initializing = true;
0851     ui.cbSymbolBorderStyle->setCurrentIndex( (int) pen.style());
0852     ui.kcbSymbolBorderColor->setColor( pen.color());
0853     GuiTools::updatePenStyles(ui.cbSymbolBorderStyle, pen.color());
0854     ui.sbSymbolBorderWidth->setValue( Worksheet::convertFromSceneUnits(pen.widthF(), Worksheet::Unit::Point));
0855     m_initializing = false;
0856 }
0857 
0858 void DatapickerImageWidget::symbolVisibleChanged(bool on) {
0859     m_initializing = true;
0860     ui.chbSymbolVisible->setChecked(on);
0861     m_initializing = false;
0862 }
0863 
0864 //**********************************************************
0865 //******************** SETTINGS ****************************
0866 //**********************************************************
0867 void DatapickerImageWidget::load() {
0868     if (!m_image)
0869         return;
0870 
0871     m_initializing = true;
0872     ui.leFileName->setText( m_image->fileName() );
0873 
0874     //highlight the text field for the background image red if an image is used and cannot be found
0875     const QString& fileName = m_image->fileName();
0876     bool invalid = (!fileName.isEmpty() && !QFile::exists(fileName));
0877     GuiTools::highlight(ui.leFileName, invalid);
0878 
0879     ui.cbGraphType->setCurrentIndex((int) m_image->axisPoints().type);
0880     ui.sbTernaryScale->setValue(m_image->axisPoints().ternaryScale);
0881     ui.sbPositionX1->setValue(m_image->axisPoints().logicalPos[0].x());
0882     ui.sbPositionY1->setValue(m_image->axisPoints().logicalPos[0].y());
0883     ui.sbPositionX2->setValue(m_image->axisPoints().logicalPos[1].x());
0884     ui.sbPositionY2->setValue(m_image->axisPoints().logicalPos[1].y());
0885     ui.sbPositionX3->setValue(m_image->axisPoints().logicalPos[2].x());
0886     ui.sbPositionY3->setValue(m_image->axisPoints().logicalPos[2].y());
0887     ui.sbPositionZ1->setValue(m_image->axisPoints().logicalPos[0].z());
0888     ui.sbPositionZ2->setValue(m_image->axisPoints().logicalPos[1].z());
0889     ui.sbPositionZ3->setValue(m_image->axisPoints().logicalPos[2].z());
0890     ui.cbPlotImageType->setCurrentIndex((int) m_image->plotImageType());
0891     ssIntensity->setSpan(m_image->settings().intensityThresholdLow, m_image->settings().intensityThresholdHigh);
0892     ssForeground->setSpan(m_image->settings().foregroundThresholdLow, m_image->settings().foregroundThresholdHigh);
0893     ssHue->setSpan(m_image->settings().hueThresholdLow, m_image->settings().hueThresholdHigh);
0894     ssSaturation->setSpan(m_image->settings().saturationThresholdLow, m_image->settings().saturationThresholdHigh);
0895     ssValue->setSpan(m_image->settings().valueThresholdLow, m_image->settings().valueThresholdHigh);
0896     gvIntensity->setSpan(m_image->settings().intensityThresholdLow, m_image->settings().intensityThresholdHigh);
0897     gvForeground->setSpan(m_image->settings().foregroundThresholdLow, m_image->settings().foregroundThresholdHigh);
0898     gvHue->setSpan(m_image->settings().hueThresholdLow, m_image->settings().hueThresholdHigh);
0899     gvSaturation->setSpan(m_image->settings().saturationThresholdLow, m_image->settings().saturationThresholdHigh);
0900     gvValue->setSpan(m_image->settings().valueThresholdLow, m_image->settings().valueThresholdHigh);
0901     ui.sbPointSeparation->setValue(m_image->pointSeparation());
0902     ui.sbMinSegmentLength->setValue(m_image->minSegmentLength());
0903     ui.cbSymbolStyle->setCurrentIndex( (int)m_image->pointStyle() - 1 );
0904     ui.sbSymbolSize->setValue( Worksheet::convertFromSceneUnits(m_image->pointSize(), Worksheet::Unit::Point) );
0905     ui.sbSymbolRotation->setValue( m_image->pointRotationAngle() );
0906     ui.sbSymbolOpacity->setValue( round(m_image->pointOpacity()*100.0) );
0907     ui.cbSymbolFillingStyle->setCurrentIndex( (int) m_image->pointBrush().style() );
0908     ui.kcbSymbolFillingColor->setColor(  m_image->pointBrush().color() );
0909     ui.cbSymbolBorderStyle->setCurrentIndex( (int) m_image->pointPen().style() );
0910     ui.kcbSymbolBorderColor->setColor( m_image->pointPen().color() );
0911     ui.sbSymbolBorderWidth->setValue( Worksheet::convertFromSceneUnits(m_image->pointPen().widthF(), Worksheet::Unit::Point) );
0912     ui.chbSymbolVisible->setChecked( m_image->pointVisibility() );
0913     m_initializing = false;
0914 }