File indexing completed on 2025-10-12 03:31:31
0001 /* 0002 File : DatapickerImageWidget.cpp 0003 Project : LabPlot 0004 Description : widget for datapicker properties 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2015-2016 Ankit Wagadre <wagadre.ankit@gmail.com> 0007 SPDX-FileCopyrightText: 2015-2021 Alexander Semke <alexander.semke@web.de> 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later 0010 */ 0011 0012 #include "DatapickerImageWidget.h" 0013 #include "backend/core/Project.h" 0014 #include "backend/datapicker/DatapickerPoint.h" 0015 #include "backend/datapicker/ImageEditor.h" 0016 #include "commonfrontend/widgets/qxtspanslider.h" 0017 #include "kdefrontend/GuiTools.h" 0018 #include "kdefrontend/widgets/SymbolWidget.h" 0019 0020 #include <KConfigGroup> 0021 #include <KLocalizedString> 0022 0023 #include <QCompleter> 0024 #include <QDir> 0025 // see https://gitlab.kitware.com/cmake/cmake/-/issues/21609 0026 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) 0027 #include <QFileSystemModel> 0028 #else 0029 #include <QDirModel> 0030 #endif 0031 #include <QGraphicsScene> 0032 #include <QPainter> 0033 #include <QStandardPaths> 0034 0035 #include <cmath> 0036 0037 HistogramView::HistogramView(QWidget* parent, int range) 0038 : QGraphicsView(parent) 0039 , m_scene(new QGraphicsScene()) 0040 , m_range(range) { 0041 setTransform(QTransform()); 0042 QRectF pageRect(0, 0, 1000, 100); 0043 m_scene->setSceneRect(pageRect); 0044 setScene(m_scene); 0045 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0046 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0047 0048 m_lowerSlider = new QGraphicsRectItem(pageRect, nullptr); 0049 m_lowerSlider->setPen(QPen(Qt::black, 0.5)); 0050 m_lowerSlider->setBrush(Qt::blue); 0051 m_lowerSlider->setOpacity(0.2); 0052 m_scene->addItem(m_lowerSlider); 0053 0054 m_upperSlider = new QGraphicsRectItem(pageRect, nullptr); 0055 m_upperSlider->setPen(QPen(Qt::black, 0.5)); 0056 m_upperSlider->setBrush(Qt::blue); 0057 m_upperSlider->setOpacity(0.2); 0058 m_scene->addItem(m_upperSlider); 0059 } 0060 0061 void HistogramView::setScalePixmap(const QString& file) { 0062 // scene rect is 1000*100 where upper 1000*80 is for histogram graph 0063 // and lower 1000*20 is for histogram scale 0064 auto* pixmap = new QGraphicsPixmapItem(QPixmap(file).scaled(1000, 20, Qt::IgnoreAspectRatio), nullptr); 0065 pixmap->setZValue(-1); 0066 pixmap->setPos(0, 90); 0067 m_scene->addItem(pixmap); 0068 } 0069 0070 void HistogramView::setSpan(int l, int h) { 0071 l = l * 1000 / m_range; 0072 h = h * 1000 / m_range; 0073 m_lowerSlider->setPos(QPointF(l - 1000, 0)); 0074 m_upperSlider->setPos(QPointF(h, 0)); 0075 invalidateScene(sceneRect(), QGraphicsScene::BackgroundLayer); 0076 } 0077 0078 void HistogramView::resizeEvent(QResizeEvent* event) { 0079 fitInView(m_scene->sceneRect(), Qt::IgnoreAspectRatio); 0080 QGraphicsView::resizeEvent(event); 0081 } 0082 0083 void HistogramView::drawBackground(QPainter* painter, const QRectF& rect) { 0084 if (!bins) 0085 return; 0086 0087 painter->save(); 0088 painter->setRenderHint(QPainter::Antialiasing, true); 0089 int max = 1; 0090 for (int i = 0; i <= m_range; i++) 0091 if (bins[i] > max) 0092 max = bins[i]; 0093 0094 // convert y-scale count to log scale so small counts are still visible 0095 // scene rect is 1000*100 where upper 1000*80 is for histogram graph 0096 // and lower 1000*20 is for histogram scale 0097 QPainterPath path(QPointF(0, (log(bins[0]) * 100 / log(max)))); 0098 for (int i = 1; i <= m_range; i++) { 0099 int x = i * 1000 / m_range; 0100 int y = 80; 0101 if (bins[i] > 1) 0102 y = 80 - (log(bins[i]) * 80 / log(max)); 0103 0104 path.lineTo(QPointF(x, y)); 0105 } 0106 0107 painter->drawPath(path); 0108 invalidateScene(rect, QGraphicsScene::BackgroundLayer); 0109 painter->restore(); 0110 } 0111 0112 DatapickerImageWidget::DatapickerImageWidget(QWidget* parent) 0113 : BaseDock(parent) 0114 , m_image(nullptr) { 0115 ui.setupUi(this); 0116 setBaseWidgets(ui.leName, ui.teComment); 0117 0118 //"General"-tab 0119 ui.leFileName->setClearButtonEnabled(true); 0120 ui.bOpen->setIcon(QIcon::fromTheme(QStringLiteral("document-open"))); 0121 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) 0122 ui.leFileName->setCompleter(new QCompleter(new QFileSystemModel, this)); 0123 #else 0124 ui.leFileName->setCompleter(new QCompleter(new QDirModel, this)); 0125 #endif 0126 0127 //"Symbol"-tab 0128 symbolWidget = new SymbolWidget(ui.tSymbol); 0129 auto* gridLayout = dynamic_cast<QGridLayout*>(ui.tSymbol->layout()); 0130 if (gridLayout) 0131 gridLayout->addWidget(symbolWidget, 0, 0, 1, 1); 0132 0133 //"Edit Image"-tab 0134 auto* editTabLayout = static_cast<QGridLayout*>(ui.tEdit->layout()); 0135 editTabLayout->setContentsMargins(2, 2, 2, 2); 0136 editTabLayout->setHorizontalSpacing(2); 0137 editTabLayout->setVerticalSpacing(4); 0138 0139 ssHue = new SpanSlider(Qt::Horizontal, ui.tEdit); 0140 ssHue->setToolTip(i18n("Select the range for the hue.\nEverything outside of this range will be set to white.")); 0141 ssHue->setRange(0, 360); 0142 editTabLayout->addWidget(ssHue, 3, 2); 0143 0144 ssSaturation = new SpanSlider(Qt::Horizontal, ui.tEdit); 0145 ssSaturation->setToolTip(i18n("Select the range for the saturation.\nEverything outside of this range will be set to white.")); 0146 ssSaturation->setRange(0, 100); 0147 editTabLayout->addWidget(ssSaturation, 5, 2); 0148 0149 ssValue = new SpanSlider(Qt::Horizontal, ui.tEdit); 0150 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.")); 0151 ssValue->setRange(0, 100); 0152 editTabLayout->addWidget(ssValue, 7, 2); 0153 0154 ssIntensity = new SpanSlider(Qt::Horizontal, ui.tEdit); 0155 ssIntensity->setToolTip(i18n("Select the range for the intensity.\nEverything outside of this range will be set to white.")); 0156 ssIntensity->setRange(0, 100); 0157 editTabLayout->addWidget(ssIntensity, 9, 2); 0158 0159 ssForeground = new SpanSlider(Qt::Horizontal, ui.tEdit); 0160 ssForeground->setToolTip( 0161 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)"), (int)DatapickerImage::GraphType::Linear); 0166 ui.cbGraphType->addItem(i18n("Polar (x, y°)"), (int)DatapickerImage::GraphType::PolarInDegree); 0167 ui.cbGraphType->addItem(i18n("Polar (x, y(rad))"), (int)DatapickerImage::GraphType::PolarInRadians); 0168 ui.cbGraphType->addItem(i18n("Logarithmic (ln(x), ln(y))"), (int)DatapickerImage::GraphType::LnXY); 0169 ui.cbGraphType->addItem(i18n("Logarithmic (ln(x), y)"), (int)DatapickerImage::GraphType::LnX); 0170 ui.cbGraphType->addItem(i18n("Logarithmic (x, ln(y))"), (int)DatapickerImage::GraphType::LnY); 0171 ui.cbGraphType->addItem(i18n("Logarithmic (log(x), log(y))"), (int)DatapickerImage::GraphType::Log10XY); 0172 ui.cbGraphType->addItem(i18n("Logarithmic (log(x), y)"), (int)DatapickerImage::GraphType::Log10X); 0173 ui.cbGraphType->addItem(i18n("Logarithmic (x, log(y))"), (int)DatapickerImage::GraphType::Log10Y); 0174 ui.cbGraphType->addItem(i18n("Ternary (x, y, z)"), (int)DatapickerImage::GraphType::Ternary); 0175 0176 ui.lTernaryScale->setHidden(true); 0177 ui.sbTernaryScale->setHidden(true); 0178 ui.lPositionZ1->setHidden(true); 0179 ui.lPositionZ2->setHidden(true); 0180 ui.lPositionZ3->setHidden(true); 0181 ui.sbPositionZ1->setHidden(true); 0182 ui.sbPositionZ2->setHidden(true); 0183 ui.sbPositionZ3->setHidden(true); 0184 0185 ui.cbPlotImageType->addItem(i18n("No Image")); 0186 ui.cbPlotImageType->addItem(i18n("Original Image")); 0187 ui.cbPlotImageType->addItem(i18n("Processed Image")); 0188 0189 QString valueFile = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("pics/colorchooser/colorchooser_value.xpm")); 0190 QString hueFile = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("pics/colorchooser/colorchooser_hue.xpm")); 0191 QString saturationFile = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("pics/colorchooser/colorchooser_saturation.xpm")); 0192 0193 gvHue = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::ColorAttributes::Hue)); 0194 gvHue->setToolTip(i18n("Select the range for the hue.\nEverything outside of this range will be set to white.")); 0195 editTabLayout->addWidget(gvHue, 2, 2); 0196 gvHue->setScalePixmap(hueFile); 0197 0198 gvSaturation = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::ColorAttributes::Saturation)); 0199 gvSaturation->setToolTip(i18n("Select the range for the saturation.\nEverything outside of this range will be set to white.")); 0200 editTabLayout->addWidget(gvSaturation, 4, 2); 0201 gvSaturation->setScalePixmap(saturationFile); 0202 0203 gvValue = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::ColorAttributes::Value)); 0204 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.")); 0205 editTabLayout->addWidget(gvValue, 6, 2); 0206 gvValue->setScalePixmap(valueFile); 0207 0208 gvIntensity = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::ColorAttributes::Intensity)); 0209 gvIntensity->setToolTip(i18n("Select the range for the intensity.\nEverything outside of this range will be set to white.")); 0210 editTabLayout->addWidget(gvIntensity, 8, 2); 0211 gvIntensity->setScalePixmap(valueFile); 0212 0213 gvForeground = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::ColorAttributes::Foreground)); 0214 gvForeground->setToolTip( 0215 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.")); 0216 editTabLayout->addWidget(gvForeground, 10, 2); 0217 gvForeground->setScalePixmap(valueFile); 0218 0219 DatapickerImageWidget::updateLocale(); 0220 0221 // SLOTS 0222 // general 0223 connect(ui.bOpen, &QPushButton::clicked, this, &DatapickerImageWidget::selectFile); 0224 connect(ui.leFileName, &QLineEdit::returnPressed, this, &DatapickerImageWidget::fileNameChanged); 0225 connect(ui.leFileName, &QLineEdit::textChanged, this, &DatapickerImageWidget::fileNameChanged); 0226 connect(ui.cbFileRelativePath, &QCheckBox::clicked, this, &DatapickerImageWidget::relativeChanged); 0227 connect(ui.cbFileEmbedd, &QCheckBox::clicked, this, &DatapickerImageWidget::embeddedChanged); 0228 0229 // edit image 0230 connect(ui.cbPlotImageType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &DatapickerImageWidget::plotImageTypeChanged); 0231 connect(ui.sbRotation, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &DatapickerImageWidget::rotationChanged); 0232 connect(ssIntensity, &SpanSlider::spanChanged, this, &DatapickerImageWidget::intensitySpanChanged); 0233 connect(ssIntensity, &SpanSlider::spanChanged, gvIntensity, &HistogramView::setSpan); 0234 connect(ssForeground, &SpanSlider::spanChanged, this, &DatapickerImageWidget::foregroundSpanChanged); 0235 connect(ssForeground, &SpanSlider::spanChanged, gvForeground, &HistogramView::setSpan); 0236 connect(ssHue, &SpanSlider::spanChanged, this, &DatapickerImageWidget::hueSpanChanged); 0237 connect(ssHue, &SpanSlider::spanChanged, gvHue, &HistogramView::setSpan); 0238 connect(ssSaturation, &SpanSlider::spanChanged, this, &DatapickerImageWidget::saturationSpanChanged); 0239 connect(ssSaturation, &SpanSlider::spanChanged, gvSaturation, &HistogramView::setSpan); 0240 connect(ssValue, &SpanSlider::spanChanged, this, &DatapickerImageWidget::valueSpanChanged); 0241 connect(ssValue, &SpanSlider::spanChanged, gvValue, &HistogramView::setSpan); 0242 connect(ui.sbMinSegmentLength, QOverload<int>::of(&QSpinBox::valueChanged), this, &DatapickerImageWidget::minSegmentLengthChanged); 0243 connect(ui.sbPointSeparation, QOverload<int>::of(&QSpinBox::valueChanged), this, &DatapickerImageWidget::pointSeparationChanged); 0244 0245 // axis point 0246 connect(ui.cbGraphType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &DatapickerImageWidget::graphTypeChanged); 0247 connect(ui.sbTernaryScale, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &DatapickerImageWidget::ternaryScaleChanged); 0248 connect(ui.sbPositionX1, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &DatapickerImageWidget::logicalPositionChanged); 0249 connect(ui.sbPositionY1, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &DatapickerImageWidget::logicalPositionChanged); 0250 connect(ui.sbPositionX2, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &DatapickerImageWidget::logicalPositionChanged); 0251 connect(ui.sbPositionY2, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &DatapickerImageWidget::logicalPositionChanged); 0252 connect(ui.sbPositionX3, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &DatapickerImageWidget::logicalPositionChanged); 0253 connect(ui.sbPositionY3, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &DatapickerImageWidget::logicalPositionChanged); 0254 connect(ui.sbPositionZ1, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &DatapickerImageWidget::logicalPositionChanged); 0255 connect(ui.sbPositionZ2, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &DatapickerImageWidget::logicalPositionChanged); 0256 connect(ui.sbPositionZ3, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &DatapickerImageWidget::logicalPositionChanged); 0257 0258 connect(ui.cbDatetime, &QCheckBox::clicked, this, &DatapickerImageWidget::dateTimeUsageChanged); 0259 connect(ui.dtePositionX1, &QDateTimeEdit::dateTimeChanged, this, &DatapickerImageWidget::logicalPositionChanged); 0260 connect(ui.dtePositionX2, &QDateTimeEdit::dateTimeChanged, this, &DatapickerImageWidget::logicalPositionChanged); 0261 connect(ui.dtePositionX3, &QDateTimeEdit::dateTimeChanged, this, &DatapickerImageWidget::logicalPositionChanged); 0262 0263 connect(ui.chbSymbolVisible, &QCheckBox::clicked, this, &DatapickerImageWidget::pointsVisibilityChanged); 0264 } 0265 0266 void DatapickerImageWidget::setImages(QList<DatapickerImage*> list) { 0267 CONDITIONAL_LOCK_RETURN; 0268 m_imagesList = list; 0269 m_image = list.first(); 0270 0271 // Set parents as aspects, because their name will be changed 0272 QList<AbstractAspect*> datapickers; 0273 for (const auto* l : list) 0274 datapickers.push_back(l->parentAspect()); 0275 setAspects(datapickers); 0276 0277 if (list.size() == 1) { 0278 ui.leName->setText(m_image->parentAspect()->name()); 0279 ui.teComment->setText(m_image->parentAspect()->comment()); 0280 } 0281 0282 this->load(); 0283 0284 QList<Symbol*> symbols; 0285 for (auto* image : m_imagesList) 0286 symbols << image->symbol(); 0287 0288 symbolWidget->setSymbols(symbols); 0289 0290 connect(m_image, &DatapickerImage::fileNameChanged, this, &DatapickerImageWidget::imageFileNameChanged); 0291 connect(m_image, &DatapickerImage::embeddedChanged, this, &DatapickerImageWidget::imageEmbeddedChanged); 0292 connect(m_image, &DatapickerImage::rotationAngleChanged, this, &DatapickerImageWidget::imageRotationAngleChanged); 0293 connect(m_image, &AbstractAspect::childAspectRemoved, this, &DatapickerImageWidget::updateSymbolWidgets); 0294 connect(m_image, &AbstractAspect::childAspectAdded, this, &DatapickerImageWidget::updateSymbolWidgets); 0295 connect(m_image, &DatapickerImage::axisPointsChanged, this, &DatapickerImageWidget::imageAxisPointsChanged); 0296 connect(m_image, &DatapickerImage::settingsChanged, this, &DatapickerImageWidget::imageEditorSettingsChanged); 0297 connect(m_image, &DatapickerImage::minSegmentLengthChanged, this, &DatapickerImageWidget::imageMinSegmentLengthChanged); 0298 connect(m_image, &DatapickerImage::pointVisibilityChanged, this, &DatapickerImageWidget::symbolVisibleChanged); 0299 connect(m_image, QOverload<int>::of(&DatapickerImage::referencePointSelected), this, &DatapickerImageWidget::imageReferencePointSelected); 0300 connect(m_image, &DatapickerImage::relativeFilePathChanged, this, &DatapickerImageWidget::imageRelativeChanged); 0301 if (m_image->project()) 0302 connect(m_image->project(), &Project::saved, this, &DatapickerImageWidget::updateFileRelativePathCheckBoxEnable); 0303 0304 handleWidgetActions(); 0305 updateSymbolWidgets(); 0306 } 0307 0308 void DatapickerImageWidget::handleWidgetActions() { 0309 const QString fileName = m_image->fileName(); 0310 const bool embedded = m_image->embedded(); 0311 const bool valid = !m_image->originalPlotImage.isNull(); 0312 const bool b = !fileName.isEmpty() || (embedded && valid); 0313 ui.leFileName->setEnabled(!embedded); 0314 updateFileRelativePathCheckBoxEnable(); 0315 ui.tEdit->setEnabled(b); 0316 ui.cbFileEmbedd->setEnabled(valid); 0317 ui.cbGraphType->setEnabled(b); 0318 ui.cbDatetime->setEnabled(b); 0319 ui.sbRotation->setEnabled(b); 0320 ui.sbPositionX1->setEnabled(b); 0321 ui.sbPositionX2->setEnabled(b); 0322 ui.sbPositionX3->setEnabled(b); 0323 ui.sbPositionY1->setEnabled(b); 0324 ui.sbPositionY2->setEnabled(b); 0325 ui.sbPositionY3->setEnabled(b); 0326 ui.dtePositionX1->setEnabled(b); 0327 ui.dtePositionX2->setEnabled(b); 0328 ui.dtePositionX3->setEnabled(b); 0329 ui.sbMinSegmentLength->setEnabled(b); 0330 ui.sbPointSeparation->setEnabled(b); 0331 0332 const bool invalid = (!fileName.isEmpty() && !QFile::exists(fileName) && !embedded); 0333 GuiTools::highlight(ui.leFileName, invalid); 0334 0335 if (b) { 0336 // upload histogram to view 0337 gvIntensity->bins = m_image->intensityBins; 0338 gvForeground->bins = m_image->foregroundBins; 0339 gvHue->bins = m_image->hueBins; 0340 gvSaturation->bins = m_image->saturationBins; 0341 gvValue->bins = m_image->valueBins; 0342 } 0343 } 0344 0345 void DatapickerImageWidget::updateXPositionWidgets(bool datetime) { 0346 ui.sbPositionX1->setVisible(!datetime); 0347 ui.sbPositionX2->setVisible(!datetime); 0348 ui.sbPositionX3->setVisible(!datetime); 0349 ui.dtePositionX1->setVisible(datetime); 0350 ui.dtePositionX2->setVisible(datetime); 0351 ui.dtePositionX3->setVisible(datetime); 0352 } 0353 0354 void DatapickerImageWidget::updateLocale() { 0355 const auto locale = QLocale(); 0356 ui.sbRotation->setLocale(locale); 0357 ui.sbPositionX1->setLocale(locale); 0358 ui.sbPositionX2->setLocale(locale); 0359 ui.sbPositionX3->setLocale(locale); 0360 ui.sbPositionY1->setLocale(locale); 0361 ui.sbPositionY2->setLocale(locale); 0362 ui.sbPositionY3->setLocale(locale); 0363 ui.dtePositionX1->setLocale(locale); 0364 ui.dtePositionX2->setLocale(locale); 0365 ui.dtePositionX3->setLocale(locale); 0366 } 0367 0368 void DatapickerImageWidget::updateFileRelativePathCheckBoxEnable() { 0369 const auto* project = m_image->project(); 0370 if (!project || project->fileName().isEmpty()) { 0371 ui.cbFileRelativePath->setEnabled(false); 0372 ui.cbFileRelativePath->setToolTip(i18n("Save project before using this option")); 0373 } else if (m_image->embedded()) { 0374 ui.cbFileRelativePath->setEnabled(false); 0375 ui.cbFileRelativePath->setToolTip(QStringLiteral("")); 0376 } else if (!m_image->fileName().isEmpty() && QFile::exists(m_image->fileName())) { 0377 ui.cbFileRelativePath->setEnabled(true); 0378 ui.cbFileRelativePath->setToolTip(QStringLiteral("")); 0379 } else { 0380 ui.cbFileRelativePath->setEnabled(false); 0381 ui.cbFileRelativePath->setToolTip(i18n("Invalid image")); 0382 } 0383 0384 ui.cbFileRelativePath->setVisible(!m_image->embedded()); 0385 } 0386 0387 //********************************************************** 0388 //****** SLOTs for changes triggered in DatapickerImageWidget ******** 0389 //********************************************************** 0390 //"General"-tab 0391 void DatapickerImageWidget::selectFile() { 0392 const QString& path = GuiTools::openImageFile(QLatin1String("DatapickerImageWidget")); 0393 if (path.isEmpty()) 0394 return; 0395 0396 ui.cbFileRelativePath->setChecked(false); 0397 ui.leFileName->setText(path); 0398 } 0399 0400 void DatapickerImageWidget::embeddedChanged(bool embedded) { 0401 CONDITIONAL_LOCK_RETURN; 0402 0403 for (auto* image : m_imagesList) 0404 image->setEmbedded(embedded); 0405 0406 // embedded property was set, update the file name LineEdit after this 0407 if (embedded) { 0408 QFileInfo fi(m_image->fileName()); 0409 ui.leFileName->setText(fi.fileName()); 0410 } else 0411 ui.leFileName->setText(m_image->fileName()); 0412 } 0413 0414 void DatapickerImageWidget::relativeChanged(bool relative) { 0415 CONDITIONAL_LOCK_RETURN; 0416 0417 for (auto* image : m_imagesList) { 0418 image->setRelativeFilePath(relative); 0419 } 0420 0421 // Load new filename 0422 ui.leFileName->setText(m_image->fileName()); 0423 } 0424 0425 void DatapickerImageWidget::fileNameChanged() { 0426 CONDITIONAL_LOCK_RETURN; 0427 0428 const QString fileName = ui.leFileName->text(); 0429 for (auto* image : m_imagesList) 0430 image->setImage(fileName, image->embedded()); 0431 } 0432 0433 void DatapickerImageWidget::graphTypeChanged(int index) { 0434 auto points = m_image->axisPoints(); 0435 points.type = static_cast<DatapickerImage::GraphType>(ui.cbGraphType->itemData(index).toInt()); 0436 0437 const bool ternary = (points.type == DatapickerImage::GraphType::Ternary); 0438 ui.lTernaryScale->setVisible(ternary); 0439 ui.sbTernaryScale->setVisible(ternary); 0440 ui.lPositionZ1->setVisible(ternary); 0441 ui.lPositionZ2->setVisible(ternary); 0442 ui.lPositionZ3->setVisible(ternary); 0443 ui.sbPositionZ1->setVisible(ternary); 0444 ui.sbPositionZ2->setVisible(ternary); 0445 ui.sbPositionZ3->setVisible(ternary); 0446 0447 CONDITIONAL_RETURN_NO_LOCK; 0448 0449 if (points.type == DatapickerImage::GraphType::LnXY || points.type == DatapickerImage::GraphType::LnX || points.type == DatapickerImage::GraphType::Log10XY 0450 || points.type == DatapickerImage::GraphType::Log10X) { 0451 if (points.logicalPos[0].x() == 0.0f) 0452 points.logicalPos[0].setX(0.01f); 0453 if (points.logicalPos[1].x() == 0.0f) 0454 points.logicalPos[1].setX(0.01f); 0455 if (points.logicalPos[2].x() == 0.0f) 0456 points.logicalPos[2].setX(0.01f); 0457 } 0458 if (points.type == DatapickerImage::GraphType::LnXY || points.type == DatapickerImage::GraphType::LnY || points.type == DatapickerImage::GraphType::Log10XY 0459 || points.type == DatapickerImage::GraphType::Log10Y) { 0460 if (points.logicalPos[0].y() == 0.0f) 0461 points.logicalPos[0].setY(0.01f); 0462 if (points.logicalPos[1].y() == 0.0f) 0463 points.logicalPos[1].setY(0.01f); 0464 if (points.logicalPos[2].y() == 0.0f) 0465 points.logicalPos[2].setY(0.01f); 0466 } 0467 0468 for (auto* image : m_imagesList) 0469 image->setAxisPoints(points); 0470 } 0471 0472 void DatapickerImageWidget::ternaryScaleChanged(double value) { 0473 CONDITIONAL_RETURN_NO_LOCK; 0474 0475 DatapickerImage::ReferencePoints points = m_image->axisPoints(); 0476 points.ternaryScale = value; 0477 0478 for (auto* image : m_imagesList) 0479 image->setAxisPoints(points); 0480 } 0481 0482 void DatapickerImageWidget::dateTimeUsageChanged(bool datetime) { 0483 updateXPositionWidgets(datetime); 0484 0485 CONDITIONAL_LOCK_RETURN; 0486 0487 auto points = m_image->axisPoints(); 0488 points.datetime = datetime; 0489 for (auto* image : m_imagesList) 0490 image->setAxisPoints(points); 0491 } 0492 0493 void DatapickerImageWidget::logicalPositionChanged() { 0494 CONDITIONAL_RETURN_NO_LOCK; 0495 0496 auto points = m_image->axisPoints(); 0497 if (points.datetime) { 0498 points.logicalPos[0].setX(ui.dtePositionX1->dateTime().toMSecsSinceEpoch()); 0499 points.logicalPos[1].setX(ui.dtePositionX2->dateTime().toMSecsSinceEpoch()); 0500 points.logicalPos[2].setX(ui.dtePositionX3->dateTime().toMSecsSinceEpoch()); 0501 } else { 0502 points.logicalPos[0].setX(ui.sbPositionX1->value()); 0503 points.logicalPos[1].setX(ui.sbPositionX2->value()); 0504 points.logicalPos[2].setX(ui.sbPositionX3->value()); 0505 } 0506 0507 points.logicalPos[0].setY(ui.sbPositionY1->value()); 0508 points.logicalPos[1].setY(ui.sbPositionY2->value()); 0509 points.logicalPos[2].setY(ui.sbPositionY3->value()); 0510 0511 points.logicalPos[0].setZ(ui.sbPositionZ1->value()); 0512 points.logicalPos[1].setZ(ui.sbPositionZ2->value()); 0513 points.logicalPos[2].setZ(ui.sbPositionZ3->value()); 0514 0515 for (auto* image : m_imagesList) 0516 image->setAxisPoints(points); 0517 } 0518 0519 void DatapickerImageWidget::pointsVisibilityChanged(bool state) { 0520 CONDITIONAL_LOCK_RETURN; 0521 0522 for (auto* image : m_imagesList) 0523 image->setPointVisibility(state); 0524 } 0525 0526 void DatapickerImageWidget::intensitySpanChanged(int lowerLimit, int upperLimit) { 0527 CONDITIONAL_LOCK_RETURN; 0528 0529 auto settings = m_image->settings(); 0530 settings.intensityThresholdHigh = upperLimit; 0531 settings.intensityThresholdLow = lowerLimit; 0532 for (auto* image : m_imagesList) 0533 image->setSettings(settings); 0534 } 0535 0536 void DatapickerImageWidget::foregroundSpanChanged(int lowerLimit, int upperLimit) { 0537 CONDITIONAL_LOCK_RETURN; 0538 0539 auto settings = m_image->settings(); 0540 settings.foregroundThresholdHigh = upperLimit; 0541 settings.foregroundThresholdLow = lowerLimit; 0542 for (auto* image : m_imagesList) 0543 image->setSettings(settings); 0544 } 0545 0546 void DatapickerImageWidget::hueSpanChanged(int lowerLimit, int upperLimit) { 0547 CONDITIONAL_LOCK_RETURN; 0548 0549 auto settings = m_image->settings(); 0550 settings.hueThresholdHigh = upperLimit; 0551 settings.hueThresholdLow = lowerLimit; 0552 for (auto* image : m_imagesList) 0553 image->setSettings(settings); 0554 } 0555 0556 void DatapickerImageWidget::saturationSpanChanged(int lowerLimit, int upperLimit) { 0557 CONDITIONAL_LOCK_RETURN; 0558 0559 auto settings = m_image->settings(); 0560 settings.saturationThresholdHigh = upperLimit; 0561 settings.saturationThresholdLow = lowerLimit; 0562 for (auto* image : m_imagesList) 0563 image->setSettings(settings); 0564 } 0565 0566 void DatapickerImageWidget::valueSpanChanged(int lowerLimit, int upperLimit) { 0567 CONDITIONAL_LOCK_RETURN; 0568 0569 auto settings = m_image->settings(); 0570 settings.valueThresholdHigh = upperLimit; 0571 settings.valueThresholdLow = lowerLimit; 0572 for (auto* image : m_imagesList) 0573 image->setSettings(settings); 0574 } 0575 0576 void DatapickerImageWidget::plotImageTypeChanged(int index) { 0577 CONDITIONAL_LOCK_RETURN; 0578 0579 for (auto* image : m_imagesList) 0580 image->setPlotImageType(DatapickerImage::PlotImageType(index)); 0581 } 0582 0583 void DatapickerImageWidget::rotationChanged(double value) { 0584 CONDITIONAL_RETURN_NO_LOCK; 0585 0586 for (auto* image : m_imagesList) 0587 image->setRotationAngle(value); 0588 } 0589 0590 void DatapickerImageWidget::minSegmentLengthChanged(int value) { 0591 CONDITIONAL_LOCK_RETURN; 0592 0593 for (auto* image : m_imagesList) 0594 image->setminSegmentLength(value); 0595 } 0596 0597 void DatapickerImageWidget::pointSeparationChanged(int value) { 0598 CONDITIONAL_LOCK_RETURN; 0599 0600 for (auto* image : m_imagesList) 0601 image->setPointSeparation(value); 0602 } 0603 0604 //******************************************************************* 0605 //******** SLOTs for changes triggered in DatapickerImage *********** 0606 //******************************************************************* 0607 void DatapickerImageWidget::imageFileNameChanged(const QString& name) { 0608 handleWidgetActions(); 0609 0610 CONDITIONAL_LOCK_RETURN; 0611 0612 ui.leFileName->setText(name); 0613 } 0614 0615 void DatapickerImageWidget::imageRotationAngleChanged(float angle) { 0616 CONDITIONAL_LOCK_RETURN; 0617 ui.sbRotation->setValue(angle); 0618 } 0619 0620 void DatapickerImageWidget::imageAxisPointsChanged(const DatapickerImage::ReferencePoints& axisPoints) { 0621 CONDITIONAL_LOCK_RETURN; 0622 int index = ui.cbGraphType->findData((int)axisPoints.type); 0623 ui.cbGraphType->setCurrentIndex(index); 0624 ui.sbTernaryScale->setValue(axisPoints.ternaryScale); 0625 ui.sbPositionX1->setValue(axisPoints.logicalPos[0].x()); 0626 ui.sbPositionY1->setValue(axisPoints.logicalPos[0].y()); 0627 ui.sbPositionX2->setValue(axisPoints.logicalPos[1].x()); 0628 ui.sbPositionY2->setValue(axisPoints.logicalPos[1].y()); 0629 ui.sbPositionX3->setValue(axisPoints.logicalPos[2].x()); 0630 ui.sbPositionY3->setValue(axisPoints.logicalPos[2].y()); 0631 ui.sbPositionZ1->setValue(axisPoints.logicalPos[0].z()); 0632 ui.sbPositionZ2->setValue(axisPoints.logicalPos[1].z()); 0633 ui.sbPositionZ3->setValue(axisPoints.logicalPos[2].z()); 0634 } 0635 0636 void DatapickerImageWidget::imageEditorSettingsChanged(const DatapickerImage::EditorSettings& settings) { 0637 CONDITIONAL_LOCK_RETURN; 0638 ssIntensity->setSpan(settings.intensityThresholdLow, settings.intensityThresholdHigh); 0639 ssForeground->setSpan(settings.foregroundThresholdLow, settings.foregroundThresholdHigh); 0640 ssHue->setSpan(settings.hueThresholdLow, settings.hueThresholdHigh); 0641 ssSaturation->setSpan(settings.saturationThresholdLow, settings.saturationThresholdHigh); 0642 ssValue->setSpan(settings.valueThresholdLow, settings.valueThresholdHigh); 0643 gvIntensity->setSpan(settings.intensityThresholdLow, settings.intensityThresholdHigh); 0644 gvForeground->setSpan(settings.foregroundThresholdLow, settings.foregroundThresholdHigh); 0645 gvHue->setSpan(settings.hueThresholdLow, settings.hueThresholdHigh); 0646 gvSaturation->setSpan(settings.saturationThresholdLow, settings.saturationThresholdHigh); 0647 gvValue->setSpan(settings.valueThresholdLow, settings.valueThresholdHigh); 0648 } 0649 0650 void DatapickerImageWidget::imageMinSegmentLengthChanged(const int value) { 0651 CONDITIONAL_LOCK_RETURN; 0652 ui.sbMinSegmentLength->setValue(value); 0653 } 0654 0655 void DatapickerImageWidget::imageEmbeddedChanged(bool embedded) { 0656 handleWidgetActions(); 0657 0658 CONDITIONAL_LOCK_RETURN; 0659 ui.cbFileEmbedd->setChecked(embedded); 0660 } 0661 0662 void DatapickerImageWidget::imageRelativeChanged(bool relative) { 0663 CONDITIONAL_LOCK_RETURN; 0664 ui.cbFileRelativePath->setChecked(relative); 0665 } 0666 0667 void DatapickerImageWidget::updateSymbolWidgets() { 0668 int pointCount = m_image->childCount<DatapickerPoint>(AbstractAspect::ChildIndexFlag::IncludeHidden); 0669 if (pointCount) 0670 ui.tSymbol->setEnabled(true); 0671 else 0672 ui.tSymbol->setEnabled(false); 0673 } 0674 0675 void DatapickerImageWidget::symbolVisibleChanged(bool on) { 0676 CONDITIONAL_LOCK_RETURN; 0677 ui.chbSymbolVisible->setChecked(on); 0678 } 0679 0680 void DatapickerImageWidget::imageReferencePointSelected(int index) { 0681 ui.rbRefPoint1->setChecked(index == 0); 0682 ui.rbRefPoint2->setChecked(index == 1); 0683 ui.rbRefPoint3->setChecked(index == 2); 0684 } 0685 0686 //********************************************************** 0687 //******************** SETTINGS **************************** 0688 //********************************************************** 0689 void DatapickerImageWidget::load() { 0690 if (!m_image) 0691 return; 0692 0693 // No lock, because it is done already in the caller function 0694 ui.cbFileEmbedd->setChecked(m_image->embedded()); 0695 embeddedChanged(m_image->embedded()); 0696 ui.cbFileRelativePath->setChecked(m_image->isRelativeFilePath()); 0697 updateFileRelativePathCheckBoxEnable(); 0698 ui.leFileName->setText(m_image->fileName()); 0699 0700 // highlight the text field for the background image red if an image is used and cannot be found 0701 const QString& fileName = m_image->fileName(); 0702 bool invalid = (!m_image->embedded() && !fileName.isEmpty() && !QFile::exists(fileName)); 0703 GuiTools::highlight(ui.leFileName, invalid); 0704 0705 imageReferencePointSelected(m_image->currentSelectedReferencePoint()); 0706 0707 ui.cbGraphType->setCurrentIndex(ui.cbGraphType->findData((int)m_image->axisPoints().type)); 0708 ui.sbTernaryScale->setValue(m_image->axisPoints().ternaryScale); 0709 const bool datetime = m_image->axisPoints().datetime; 0710 ui.cbDatetime->setChecked(datetime); 0711 updateXPositionWidgets(datetime); 0712 0713 const double x1 = m_image->axisPoints().logicalPos[0].x(); 0714 const double x2 = m_image->axisPoints().logicalPos[1].x(); 0715 const double x3 = m_image->axisPoints().logicalPos[2].x(); 0716 0717 ui.dtePositionX1->setMSecsSinceEpochUTC(x1); 0718 ui.dtePositionX2->setMSecsSinceEpochUTC(x2); 0719 ui.dtePositionX3->setMSecsSinceEpochUTC(x3); 0720 0721 ui.sbPositionX1->setValue(x1); 0722 ui.sbPositionY1->setValue(m_image->axisPoints().logicalPos[0].y()); 0723 ui.sbPositionX2->setValue(x2); 0724 ui.sbPositionY2->setValue(m_image->axisPoints().logicalPos[1].y()); 0725 ui.sbPositionX3->setValue(x3); 0726 ui.sbPositionY3->setValue(m_image->axisPoints().logicalPos[2].y()); 0727 ui.sbPositionZ1->setValue(m_image->axisPoints().logicalPos[0].z()); 0728 ui.sbPositionZ2->setValue(m_image->axisPoints().logicalPos[1].z()); 0729 ui.sbPositionZ3->setValue(m_image->axisPoints().logicalPos[2].z()); 0730 ui.cbPlotImageType->setCurrentIndex((int)m_image->plotImageType()); 0731 ssIntensity->setSpan(m_image->settings().intensityThresholdLow, m_image->settings().intensityThresholdHigh); 0732 ssForeground->setSpan(m_image->settings().foregroundThresholdLow, m_image->settings().foregroundThresholdHigh); 0733 ssHue->setSpan(m_image->settings().hueThresholdLow, m_image->settings().hueThresholdHigh); 0734 ssSaturation->setSpan(m_image->settings().saturationThresholdLow, m_image->settings().saturationThresholdHigh); 0735 ssValue->setSpan(m_image->settings().valueThresholdLow, m_image->settings().valueThresholdHigh); 0736 gvIntensity->setSpan(m_image->settings().intensityThresholdLow, m_image->settings().intensityThresholdHigh); 0737 gvForeground->setSpan(m_image->settings().foregroundThresholdLow, m_image->settings().foregroundThresholdHigh); 0738 gvHue->setSpan(m_image->settings().hueThresholdLow, m_image->settings().hueThresholdHigh); 0739 gvSaturation->setSpan(m_image->settings().saturationThresholdLow, m_image->settings().saturationThresholdHigh); 0740 gvValue->setSpan(m_image->settings().valueThresholdLow, m_image->settings().valueThresholdHigh); 0741 ui.sbPointSeparation->setValue(m_image->pointSeparation()); 0742 ui.sbMinSegmentLength->setValue(m_image->minSegmentLength()); 0743 ui.chbSymbolVisible->setChecked(m_image->pointVisibility()); 0744 }