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 }