diff --git a/src/backend/datapicker/DatapickerImage.cpp b/src/backend/datapicker/DatapickerImage.cpp index 1e5933515..a4e62d2c2 100644 --- a/src/backend/datapicker/DatapickerImage.cpp +++ b/src/backend/datapicker/DatapickerImage.cpp @@ -1,816 +1,712 @@ /*************************************************************************** File : DatapickerImage.cpp Project : LabPlot Description : Worksheet for Datapicker -------------------------------------------------------------------- Copyright : (C) 2015 by Ankit Wagadre (wagadre.ankit@gmail.com) - Copyright : (C) 2015-2016 by Alexander Semke (alexander.semke@web.de) + Copyright : (C) 2015-2019 by Alexander Semke (alexander.semke@web.de) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "DatapickerImage.h" #include "DatapickerImagePrivate.h" #include "backend/datapicker/ImageEditor.h" #include "backend/lib/commandtemplates.h" #include "backend/lib/XmlStreamReader.h" #include "backend/datapicker/DatapickerPoint.h" #include "backend/datapicker/Segments.h" #include "backend/worksheet/Worksheet.h" #include "commonfrontend/datapicker/DatapickerImageView.h" #include "kdefrontend/worksheet/ExportWorksheetDialog.h" #include #include #include #include #include #include #include #include #include /** * \class DatapickerImage * \brief container to open image/plot. * * Top-level container for DatapickerPoint. * * * \ingroup datapicker */ DatapickerImage::DatapickerImage(const QString& name, bool loading) : AbstractPart(name, AspectType::DatapickerImage), foregroundBins( new int[ImageEditor::colorAttributeMax(Foreground) + 1]), hueBins( new int[ImageEditor::colorAttributeMax(Hue) + 1]), saturationBins( new int[ImageEditor::colorAttributeMax(Saturation) + 1]), valueBins( new int[ImageEditor::colorAttributeMax(Value) + 1]), intensityBins( new int[ImageEditor::colorAttributeMax(Intensity) + 1]), d(new DatapickerImagePrivate(this)), m_segments(new Segments(this)) { if (!loading) init(); } DatapickerImage::~DatapickerImage() { delete [] hueBins; delete [] saturationBins; delete [] valueBins; delete [] intensityBins; delete [] foregroundBins; delete m_segments; delete d; } void DatapickerImage::init() { KConfig config; KConfigGroup group = config.group( "DatapickerImage" ); d->fileName = group.readEntry("FileName", QString()); d->rotationAngle = group.readEntry("RotationAngle", 0.0); d->minSegmentLength = group.readEntry("MinSegmentLength", 30); d->pointSeparation = group.readEntry("PointSeparation", 30); d->axisPoints.type = (DatapickerImage::GraphType) group.readEntry("GraphType", (int) DatapickerImage::Cartesian); d->axisPoints.ternaryScale = group.readEntry("TernaryScale", 1); d->settings.foregroundThresholdHigh = group.readEntry("ForegroundThresholdHigh", 90); d->settings.foregroundThresholdLow = group.readEntry("ForegroundThresholdLow", 30); d->settings.hueThresholdHigh = group.readEntry("HueThresholdHigh", 360); d->settings.hueThresholdLow = group.readEntry("HueThresholdLow", 0); d->settings.intensityThresholdHigh = group.readEntry("IntensityThresholdHigh", 100); d->settings.intensityThresholdLow = group.readEntry("IntensityThresholdLow", 20); d->settings.saturationThresholdHigh = group.readEntry("SaturationThresholdHigh", 100); d->settings.saturationThresholdLow = group.readEntry("SaturationThresholdLow", 30); d->settings.valueThresholdHigh = group.readEntry("ValueThresholdHigh", 90); d->settings.valueThresholdLow = group.readEntry("ValueThresholdLow", 30); d->plotPointsType = (DatapickerImage::PointsType) group.readEntry("PlotPointsType", (int) DatapickerImage::AxisPoints); d->plotImageType = DatapickerImage::OriginalImage; // point properties d->pointStyle = (Symbol::Style)group.readEntry("PointStyle", (int)Symbol::Cross); d->pointSize = group.readEntry("Size", Worksheet::convertToSceneUnits(7, Worksheet::Point)); d->pointRotationAngle = group.readEntry("Rotation", 0.0); d->pointOpacity = group.readEntry("Opacity", 1.0); d->pointBrush.setStyle( (Qt::BrushStyle)group.readEntry("FillingStyle", (int)Qt::NoBrush) ); d->pointBrush.setColor( group.readEntry("FillingColor", QColor(Qt::black)) ); d->pointPen.setStyle( (Qt::PenStyle)group.readEntry("BorderStyle", (int)Qt::SolidLine) ); d->pointPen.setColor( group.readEntry("BorderColor", QColor(Qt::red)) ); d->pointPen.setWidthF( group.readEntry("BorderWidth", Worksheet::convertToSceneUnits(1, Worksheet::Point)) ); d->pointVisibility = group.readEntry("PointVisibility", true); } /*! Returns an icon to be used in the project explorer. */ QIcon DatapickerImage::icon() const { return QIcon::fromTheme("image-x-generic"); } /*! Return a new context menu */ QMenu* DatapickerImage::createContextMenu() { QMenu* menu = new QMenu(nullptr); emit requestProjectContextMenu(menu); return menu; } void DatapickerImage::createContextMenu(QMenu* menu) { emit requestProjectContextMenu(menu); } //! Construct a primary view on me. /** * This method may be called multiple times during the life time of an Aspect, or it might not get * called at all. Aspects must not depend on the existence of a view for their operation. */ QWidget* DatapickerImage::view() const { if (!m_partView) { m_view = new DatapickerImageView(const_cast(this)); m_partView = m_view; connect(m_view, &DatapickerImageView::statusInfo, this, &DatapickerImage::statusInfo); } return m_partView; } bool DatapickerImage::exportView() const { auto* dlg = new ExportWorksheetDialog(m_view); dlg->setFileName(name()); bool ret; if ( (ret = (dlg->exec() == QDialog::Accepted)) ) { const QString path = dlg->path(); const WorksheetView::ExportFormat format = dlg->exportFormat(); const int resolution = dlg->exportResolution(); WAIT_CURSOR; m_view->exportToFile(path, format, resolution); RESET_CURSOR; } delete dlg; return ret; } bool DatapickerImage::printView() { QPrinter printer; auto* dlg = new QPrintDialog(&printer, m_view); bool ret; dlg->setWindowTitle(i18nc("@title:window", "Print Datapicker Image")); if ( (ret = (dlg->exec() == QDialog::Accepted)) ) m_view->print(&printer); delete dlg; return ret; } bool DatapickerImage::printPreview() const { QPrintPreviewDialog* dlg = new QPrintPreviewDialog(m_view); connect(dlg, &QPrintPreviewDialog::paintRequested, m_view, &DatapickerImageView::print); return dlg->exec(); } /*! Selects or deselects the Datapicker/DatapickerImage in the project explorer. This function is called in \c DatapickerImageView. The DatapickerImage gets deselected if there are selected items in the view, and selected if there are no selected items in the view. */ void DatapickerImage::setSelectedInView(const bool b) { if (b) emit childAspectSelectedInView(this); else emit childAspectDeselectedInView(this); } void DatapickerImage::setSegmentsHoverEvent(const bool on) { m_segments->setAcceptHoverEvents(on); } QGraphicsScene* DatapickerImage::scene() const { return d->m_scene; } QRectF DatapickerImage::pageRect() const { return d->m_scene->sceneRect(); } void DatapickerImage::setPlotImageType(const DatapickerImage::PlotImageType type) { d->plotImageType = type; if (d->plotImageType == DatapickerImage::ProcessedImage) d->discretize(); emit requestUpdate(); } DatapickerImage::PlotImageType DatapickerImage::plotImageType() { return d->plotImageType; } void DatapickerImage::initSceneParameters() { setRotationAngle(0.0); setminSegmentLength(30); setPointSeparation(30); ReferencePoints axisPoints = d->axisPoints; axisPoints.ternaryScale = 1; axisPoints.type = DatapickerImage::Cartesian; setAxisPoints(axisPoints); EditorSettings settings; settings.foregroundThresholdHigh = 90; settings.foregroundThresholdLow = 30; settings.hueThresholdHigh = 360; settings.hueThresholdLow = 0; settings.intensityThresholdHigh = 100; settings.intensityThresholdLow = 20; settings.saturationThresholdHigh = 100; settings.saturationThresholdLow = 30; settings.valueThresholdHigh = 90; settings.valueThresholdLow = 30; setSettings(settings); DatapickerImage::PointsType plotPointsType = DatapickerImage::AxisPoints; setPlotPointsType(plotPointsType); } /* =============================== getter methods for background options ================================= */ CLASS_D_READER_IMPL(DatapickerImage, QString, fileName, fileName) CLASS_D_READER_IMPL(DatapickerImage, DatapickerImage::ReferencePoints, axisPoints, axisPoints) CLASS_D_READER_IMPL(DatapickerImage, DatapickerImage::EditorSettings, settings, settings) BASIC_D_READER_IMPL(DatapickerImage, float, rotationAngle, rotationAngle) BASIC_D_READER_IMPL(DatapickerImage, DatapickerImage::PointsType, plotPointsType, plotPointsType) BASIC_D_READER_IMPL(DatapickerImage, int, pointSeparation, pointSeparation) BASIC_D_READER_IMPL(DatapickerImage, int, minSegmentLength, minSegmentLength) BASIC_D_READER_IMPL(DatapickerImage, Symbol::Style, pointStyle, pointStyle) BASIC_D_READER_IMPL(DatapickerImage, qreal, pointOpacity, pointOpacity) BASIC_D_READER_IMPL(DatapickerImage, qreal, pointRotationAngle, pointRotationAngle) BASIC_D_READER_IMPL(DatapickerImage, qreal, pointSize, pointSize) CLASS_D_READER_IMPL(DatapickerImage, QBrush, pointBrush, pointBrush) CLASS_D_READER_IMPL(DatapickerImage, QPen, pointPen, pointPen) BASIC_D_READER_IMPL(DatapickerImage, bool, pointVisibility, pointVisibility) /* ============================ setter methods and undo commands for background options ================= */ STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetFileName, QString, fileName, updateFileName) void DatapickerImage::setFileName(const QString& fileName) { if (fileName!= d->fileName) { beginMacro(i18n("%1: upload new image", name())); exec(new DatapickerImageSetFileNameCmd(d, fileName, ki18n("%1: upload image"))); endMacro(); } } STD_SETTER_CMD_IMPL_S(DatapickerImage, SetRotationAngle, float, rotationAngle) void DatapickerImage::setRotationAngle(float angle) { if (angle != d->rotationAngle) exec(new DatapickerImageSetRotationAngleCmd(d, angle, ki18n("%1: set rotation angle"))); } STD_SETTER_CMD_IMPL_S(DatapickerImage, SetAxisPoints, DatapickerImage::ReferencePoints, axisPoints) void DatapickerImage::setAxisPoints(const DatapickerImage::ReferencePoints& points) { if (memcmp(&points, &d->axisPoints, sizeof(points)) != 0) exec(new DatapickerImageSetAxisPointsCmd(d, points, ki18n("%1: set Axis points"))); } STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetSettings, DatapickerImage::EditorSettings, settings, discretize) void DatapickerImage::setSettings(const DatapickerImage::EditorSettings& editorSettings) { if (memcmp(&editorSettings, &d->settings, sizeof(editorSettings)) != 0) exec(new DatapickerImageSetSettingsCmd(d, editorSettings, ki18n("%1: set editor settings"))); } STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetMinSegmentLength, int, minSegmentLength, makeSegments) void DatapickerImage::setminSegmentLength(const int value) { if (d->minSegmentLength != value) exec(new DatapickerImageSetMinSegmentLengthCmd(d, value, ki18n("%1: set minimum segment length"))); ; } STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetPointStyle, Symbol::Style, pointStyle, retransform) void DatapickerImage::setPointStyle(Symbol::Style newStyle) { if (newStyle != d->pointStyle) exec(new DatapickerImageSetPointStyleCmd(d, newStyle, ki18n("%1: set point's style"))); } STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetPointSize, qreal, pointSize, retransform) void DatapickerImage::setPointSize(qreal value) { if (!qFuzzyCompare(1 + value, 1 + d->pointSize)) exec(new DatapickerImageSetPointSizeCmd(d, value, ki18n("%1: set point's size"))); } STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetPointRotationAngle, qreal, pointRotationAngle, retransform) void DatapickerImage::setPointRotationAngle(qreal angle) { if (!qFuzzyCompare(1 + angle, 1 + d->pointRotationAngle)) exec(new DatapickerImageSetPointRotationAngleCmd(d, angle, ki18n("%1: rotate point"))); } STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetPointBrush, QBrush, pointBrush, retransform) void DatapickerImage::setPointBrush(const QBrush& newBrush) { if (newBrush != d->pointBrush) exec(new DatapickerImageSetPointBrushCmd(d, newBrush, ki18n("%1: set point's filling"))); } STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetPointPen, QPen, pointPen, retransform) void DatapickerImage::setPointPen(const QPen &newPen) { if (newPen != d->pointPen) exec(new DatapickerImageSetPointPenCmd(d, newPen, ki18n("%1: set outline style"))); } STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetPointOpacity, qreal, pointOpacity, retransform) void DatapickerImage::setPointOpacity(qreal newOpacity) { if (newOpacity != d->pointOpacity) exec(new DatapickerImageSetPointOpacityCmd(d, newOpacity, ki18n("%1: set point's opacity"))); } STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetPointVisibility, bool, pointVisibility, retransform) void DatapickerImage::setPointVisibility(const bool on) { if (on != d->pointVisibility) exec(new DatapickerImageSetPointVisibilityCmd(d, on, on ? ki18n("%1: set visible") : ki18n("%1: set invisible"))); } void DatapickerImage::setPrinting(bool on) const { QVector childPoints = parentAspect()->children(AbstractAspect::Recursive | AbstractAspect::IncludeHidden); for (auto* point : childPoints) point->setPrinting(on); } void DatapickerImage::setPlotPointsType(const PointsType pointsType) { d->plotPointsType = pointsType; if (pointsType == DatapickerImage::AxisPoints) { //clear image int childCount = this->childCount(AbstractAspect::IncludeHidden); if (childCount) { beginMacro(i18n("%1: remove all axis points", name())); QVector childrenPoints = children(AbstractAspect::IncludeHidden); for (auto* point : childrenPoints) point->remove(); endMacro(); } m_segments->setSegmentsVisible(false); } else if (pointsType == DatapickerImage::CurvePoints) m_segments->setSegmentsVisible(false); else if (pointsType == DatapickerImage::SegmentPoints) { d->makeSegments(); m_segments->setSegmentsVisible(true); } } void DatapickerImage::setPointSeparation(const int value) { d->pointSeparation = value; } //############################################################################## //###################### Private implementation ############################### //############################################################################## DatapickerImagePrivate::DatapickerImagePrivate(DatapickerImage *owner) : q(owner), pageRect(0, 0, 1500, 1500), m_scene(new QGraphicsScene(pageRect)) { } QString DatapickerImagePrivate::name() const { return q->name(); } void DatapickerImagePrivate::retransform() { QVector childrenPoints = q->children(AbstractAspect::IncludeHidden); for (auto* point : childrenPoints) point->retransform(); } bool DatapickerImagePrivate::uploadImage(const QString& address) { bool rc = q->originalPlotImage.load(address); if (rc) { //convert the image to 32bit-format if this is not the case yet QImage::Format format = q->originalPlotImage.format(); if (format != QImage::Format_RGB32 && format != QImage::Format_ARGB32 && format != QImage::Format_ARGB32_Premultiplied) q->originalPlotImage = q->originalPlotImage.convertToFormat(QImage::Format_RGB32); q->processedPlotImage = q->originalPlotImage; q->background = ImageEditor::findBackgroundColor(&q->originalPlotImage); //upload Histogram ImageEditor::uploadHistogram(q->intensityBins, &q->originalPlotImage, q->background, DatapickerImage::Intensity); ImageEditor::uploadHistogram(q->foregroundBins, &q->originalPlotImage, q->background, DatapickerImage::Foreground); ImageEditor::uploadHistogram(q->hueBins, &q->originalPlotImage, q->background, DatapickerImage::Hue); ImageEditor::uploadHistogram(q->saturationBins, &q->originalPlotImage, q->background, DatapickerImage::Saturation); ImageEditor::uploadHistogram(q->valueBins, &q->originalPlotImage, q->background, DatapickerImage::Value); discretize(); //resize the screen double w = Worksheet::convertToSceneUnits(q->originalPlotImage.width(), Worksheet::Inch)/QApplication::desktop()->physicalDpiX(); double h = Worksheet::convertToSceneUnits(q->originalPlotImage.height(), Worksheet::Inch)/QApplication::desktop()->physicalDpiX(); m_scene->setSceneRect(0, 0, w, h); q->isLoaded = true; } return rc; } void DatapickerImagePrivate::discretize() { if (plotImageType != DatapickerImage::ProcessedImage) return; ImageEditor::discretize(&q->processedPlotImage, &q->originalPlotImage, settings, q->background); if (plotPointsType != DatapickerImage::SegmentPoints) emit q->requestUpdate(); else makeSegments(); } void DatapickerImagePrivate::makeSegments() { if (plotPointsType != DatapickerImage::SegmentPoints) return; q->m_segments->makeSegments(q->processedPlotImage); q->m_segments->setSegmentsVisible(true); emit q->requestUpdate(); } DatapickerImagePrivate::~DatapickerImagePrivate() { delete m_scene; } void DatapickerImagePrivate::updateFileName() { WAIT_CURSOR; q->isLoaded = false; const QString& address = fileName.trimmed(); if (!address.isEmpty()) { if (uploadImage(address)) { q->initSceneParameters(); fileName = address; } } else { //hide segments if they are visible q->m_segments->setSegmentsVisible(false); } QVector childPoints = q->parentAspect()->children(AbstractAspect::Recursive | AbstractAspect::IncludeHidden); if (childPoints.count()) { for (auto* point : childPoints) point->remove(); } emit q->requestUpdate(); emit q->requestUpdateActions(); RESET_CURSOR; } //############################################################################## //################## Serialization/Deserialization ########################### //############################################################################## //! Save as XML void DatapickerImage::save(QXmlStreamWriter* writer) const { writer->writeStartElement( "datapickerImage" ); writeBasicAttributes(writer); writeCommentElement(writer); //general properties writer->writeStartElement( "general" ); writer->writeAttribute( "fileName", d->fileName ); writer->writeAttribute( "plotPointsType", QString::number(d->plotPointsType) ); writer->writeEndElement(); writer->writeStartElement( "axisPoint" ); writer->writeAttribute( "graphType", QString::number(d->axisPoints.type) ); writer->writeAttribute( "ternaryScale", QString::number(d->axisPoints.ternaryScale) ); writer->writeAttribute( "axisPointLogicalX1", QString::number(d->axisPoints.logicalPos[0].x()) ); writer->writeAttribute( "axisPointLogicalY1", QString::number(d->axisPoints.logicalPos[0].y()) ); writer->writeAttribute( "axisPointLogicalX2", QString::number(d->axisPoints.logicalPos[1].x()) ); writer->writeAttribute( "axisPointLogicalY2", QString::number(d->axisPoints.logicalPos[1].y()) ); writer->writeAttribute( "axisPointLogicalX3", QString::number(d->axisPoints.logicalPos[2].x()) ); writer->writeAttribute( "axisPointLogicalY3", QString::number(d->axisPoints.logicalPos[2].y()) ); writer->writeAttribute( "axisPointLogicalZ1", QString::number(d->axisPoints.logicalPos[0].z()) ); writer->writeAttribute( "axisPointLogicalZ2", QString::number(d->axisPoints.logicalPos[1].z()) ); writer->writeAttribute( "axisPointLogicalZ3", QString::number(d->axisPoints.logicalPos[2].z()) ); writer->writeAttribute( "axisPointSceneX1", QString::number(d->axisPoints.scenePos[0].x()) ); writer->writeAttribute( "axisPointSceneY1", QString::number(d->axisPoints.scenePos[0].y()) ); writer->writeAttribute( "axisPointSceneX2", QString::number(d->axisPoints.scenePos[1].x()) ); writer->writeAttribute( "axisPointSceneY2", QString::number(d->axisPoints.scenePos[1].y()) ); writer->writeAttribute( "axisPointSceneX3", QString::number(d->axisPoints.scenePos[2].x()) ); writer->writeAttribute( "axisPointSceneY3", QString::number(d->axisPoints.scenePos[2].y()) ); writer->writeEndElement(); //editor and segment settings writer->writeStartElement( "editorSettings" ); writer->writeAttribute( "plotImageType", QString::number(d->plotImageType) ); writer->writeAttribute( "rotationAngle", QString::number(d->rotationAngle) ); writer->writeAttribute( "minSegmentLength", QString::number(d->minSegmentLength) ); writer->writeAttribute( "pointSeparation", QString::number(d->pointSeparation) ); writer->writeAttribute( "foregroundThresholdHigh", QString::number(d->settings.foregroundThresholdHigh) ); writer->writeAttribute( "foregroundThresholdLow", QString::number(d->settings.foregroundThresholdLow) ); writer->writeAttribute( "hueThresholdHigh", QString::number(d->settings.hueThresholdHigh) ); writer->writeAttribute( "hueThresholdLow", QString::number(d->settings.hueThresholdLow) ); writer->writeAttribute( "intensityThresholdHigh", QString::number(d->settings.intensityThresholdHigh) ); writer->writeAttribute( "intensityThresholdLow", QString::number(d->settings.intensityThresholdLow) ); writer->writeAttribute( "saturationThresholdHigh", QString::number(d->settings.saturationThresholdHigh) ); writer->writeAttribute( "saturationThresholdLow", QString::number(d->settings.saturationThresholdLow) ); writer->writeAttribute( "valueThresholdHigh", QString::number(d->settings.valueThresholdHigh) ); writer->writeAttribute( "valueThresholdLow", QString::number(d->settings.valueThresholdLow) ); writer->writeEndElement(); //symbol properties writer->writeStartElement( "symbolProperties" ); writer->writeAttribute( "pointRotationAngle", QString::number(d->pointRotationAngle) ); writer->writeAttribute( "pointOpacity", QString::number(d->pointOpacity) ); writer->writeAttribute( "pointSize", QString::number(d->pointSize) ); writer->writeAttribute( "pointStyle", QString::number(d->pointStyle) ); writer->writeAttribute( "pointVisibility", QString::number(d->pointVisibility) ); WRITE_QBRUSH(d->pointBrush); WRITE_QPEN(d->pointPen); writer->writeEndElement(); //serialize all children for (auto* child : children(IncludeHidden)) child->save(writer); writer->writeEndElement(); } //! Load from XML bool DatapickerImage::load(XmlStreamReader* reader, bool preview) { if (!readBasicAttributes(reader)) return false; KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used"); QXmlStreamAttributes attribs; QString str; while (!reader->atEnd()) { reader->readNext(); if (reader->isEndElement() && reader->name() == "datapickerImage") break; if (!reader->isStartElement()) continue; if (reader->name() == "comment") { if (!readCommentElement(reader)) return false; } else if (!preview && reader->name() == "general") { attribs = reader->attributes(); str = attribs.value("fileName").toString(); d->fileName = str; str = attribs.value("plotPointsType").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("plotPointsType").toString()); else d->plotPointsType = DatapickerImage::PointsType(str.toInt()); } else if (!preview && reader->name() == "axisPoint") { attribs = reader->attributes(); - str = attribs.value("graphType").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("graphType").toString()); - else - d->axisPoints.type = DatapickerImage::GraphType(str.toInt()); - - str = attribs.value("ternaryScale").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("ternaryScale").toString()); - else - d->axisPoints.ternaryScale = str.toDouble(); + READ_INT_VALUE("graphType", axisPoints.type, DatapickerImage::GraphType); + READ_INT_VALUE("ternaryScale", axisPoints.ternaryScale, int); str = attribs.value("axisPointLogicalX1").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointLogicalX1").toString()); else d->axisPoints.logicalPos[0].setX(str.toDouble()); str = attribs.value("axisPointLogicalY1").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointLogicalY1").toString()); else d->axisPoints.logicalPos[0].setY(str.toDouble()); str = attribs.value("axisPointLogicalZ1").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointLogicalZ1").toString()); else d->axisPoints.logicalPos[0].setZ(str.toDouble()); str = attribs.value("axisPointLogicalX2").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointLogicalX2").toString()); else d->axisPoints.logicalPos[1].setX(str.toDouble()); str = attribs.value("axisPointLogicalY2").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointLogicalY2").toString()); else d->axisPoints.logicalPos[1].setY(str.toDouble()); str = attribs.value("axisPointLogicalZ2").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointLogicalZ2").toString()); else d->axisPoints.logicalPos[1].setZ(str.toDouble()); str = attribs.value("axisPointLogicalX3").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointLogicalX3").toString()); else d->axisPoints.logicalPos[2].setX(str.toDouble()); str = attribs.value("axisPointLogicalY3").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointLogicalY3").toString()); else d->axisPoints.logicalPos[2].setY(str.toDouble()); str = attribs.value("axisPointLogicalZ3").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointLogicalZ3").toString()); else d->axisPoints.logicalPos[2].setZ(str.toDouble()); str = attribs.value("axisPointSceneX1").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointSceneX1").toString()); else d->axisPoints.scenePos[0].setX(str.toDouble()); str = attribs.value("axisPointSceneY1").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointSceneY1").toString()); else d->axisPoints.scenePos[0].setY(str.toDouble()); str = attribs.value("axisPointSceneX2").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointSceneX2").toString()); else d->axisPoints.scenePos[1].setX(str.toDouble()); str = attribs.value("axisPointSceneY2").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointSceneY2").toString()); else d->axisPoints.scenePos[1].setY(str.toDouble()); str = attribs.value("axisPointSceneX3").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointSceneX3").toString()); else d->axisPoints.scenePos[2].setX(str.toDouble()); str = attribs.value("axisPointSceneY3").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("axisPointSceneY3").toString()); else d->axisPoints.scenePos[2].setY(str.toDouble()); } else if (!preview && reader->name() == "editorSettings") { attribs = reader->attributes(); - str = attribs.value("plotImageType").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("plotImageType").toString()); - else - d->plotImageType = DatapickerImage::PlotImageType(str.toInt()); - - str = attribs.value("rotationAngle").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("rotationAngle").toString()); - else - d->rotationAngle = str.toFloat(); - - str = attribs.value("minSegmentLength").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("minSegmentLength").toString()); - else - d->minSegmentLength = str.toInt(); - - str = attribs.value("pointSeparation").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("pointSeparation").toString()); - else - d->pointSeparation = str.toInt(); - - str = attribs.value("foregroundThresholdHigh").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("foregroundThresholdHigh").toString()); - else - d->settings.foregroundThresholdHigh = str.toInt(); - - str = attribs.value("foregroundThresholdLow").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("foregroundThresholdLow").toString()); - else - d->settings.foregroundThresholdLow = str.toInt(); - - str = attribs.value("hueThresholdHigh").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("hueThresholdHigh").toString()); - else - d->settings.hueThresholdHigh = str.toInt(); - - str = attribs.value("hueThresholdLow").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("hueThresholdLow").toString()); - else - d->settings.hueThresholdLow = str.toInt(); - - str = attribs.value("intensityThresholdHigh").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("intensityThresholdHigh").toString()); - else - d->settings.intensityThresholdHigh = str.toInt(); - - str = attribs.value("intensityThresholdLow").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("intensityThresholdLow").toString()); - else - d->settings.intensityThresholdLow = str.toInt(); - - str = attribs.value("saturationThresholdHigh").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("saturationThresholdHigh").toString()); - else - d->settings.saturationThresholdHigh = str.toInt(); - - str = attribs.value("saturationThresholdLow").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("saturationThresholdLow").toString()); - else - d->settings.saturationThresholdLow = str.toInt(); - - str = attribs.value("valueThresholdHigh").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("valueThresholdHigh").toString()); - else - d->settings.valueThresholdHigh = str.toInt(); - - str = attribs.value("valueThresholdLow").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("valueThresholdLow").toString()); - else - d->settings.valueThresholdLow = str.toInt(); - + READ_INT_VALUE("plotImageType", plotImageType, DatapickerImage::PlotImageType); + READ_DOUBLE_VALUE("rotationAngle", rotationAngle); + READ_INT_VALUE("minSegmentLength", minSegmentLength, int); + READ_INT_VALUE("pointSeparation", pointSeparation, int); + READ_INT_VALUE("foregroundThresholdHigh", settings.foregroundThresholdHigh, int); + READ_INT_VALUE("foregroundThresholdLow", settings.foregroundThresholdLow, int); + READ_INT_VALUE("hueThresholdHigh", settings.hueThresholdHigh, int); + READ_INT_VALUE("hueThresholdLow", settings.hueThresholdLow, int); + READ_INT_VALUE("intensityThresholdHigh", settings.intensityThresholdHigh, int); + READ_INT_VALUE("intensityThresholdLow", settings.intensityThresholdLow, int); + READ_INT_VALUE("saturationThresholdHigh", settings.saturationThresholdHigh, int); + READ_INT_VALUE("saturationThresholdLow", settings.saturationThresholdLow, int); + READ_INT_VALUE("valueThresholdHigh", settings.valueThresholdHigh, int); + READ_INT_VALUE("valueThresholdLow", settings.valueThresholdLow, int); } else if (!preview && reader->name() == "symbolProperties") { attribs = reader->attributes(); - str = attribs.value("pointRotationAngle").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("pointRotationAngle").toString()); - else - d->pointRotationAngle = str.toFloat(); - - str = attribs.value("pointOpacity").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("pointOpacity").toString()); - else - d->pointOpacity = str.toFloat(); - - str = attribs.value("pointSize").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("pointSize").toString()); - else - d->pointSize = str.toFloat(); - - str = attribs.value("pointStyle").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("pointStyle").toString()); - else - d->pointStyle = (Symbol::Style)str.toInt(); - - str = attribs.value("pointVisibility").toString(); - if (str.isEmpty()) - reader->raiseWarning(attributeWarning.subs("pointVisibility").toString()); - else - d->pointVisibility = (bool)str.toInt(); - + READ_DOUBLE_VALUE("pointRotationAngle", pointRotationAngle); + READ_DOUBLE_VALUE("pointOpacity", pointOpacity); + READ_DOUBLE_VALUE("pointSize", pointSize); + READ_INT_VALUE("pointStyle", pointStyle, Symbol::Style); + READ_INT_VALUE("pointVisibility", pointVisibility, bool); READ_QBRUSH(d->pointBrush); READ_QPEN(d->pointPen); } else if (reader->name() == "datapickerPoint") { DatapickerPoint* datapickerPoint = new DatapickerPoint(QString()); datapickerPoint->setHidden(true); if (!datapickerPoint->load(reader, preview)) { delete datapickerPoint; return false; } else addChild(datapickerPoint); } else { // unknown element reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString())); if (!reader->skipToEndElement()) return false; } } d->uploadImage(d->fileName); d->retransform(); return true; } diff --git a/src/kdefrontend/widgets/DatapickerImageWidget.cpp b/src/kdefrontend/widgets/DatapickerImageWidget.cpp index 6397816e1..204510953 100644 --- a/src/kdefrontend/widgets/DatapickerImageWidget.cpp +++ b/src/kdefrontend/widgets/DatapickerImageWidget.cpp @@ -1,863 +1,865 @@ /*************************************************************************** File : DatapickerImageWidget.cpp Project : LabPlot Description : widget for datapicker properties -------------------------------------------------------------------- Copyright : (C) 2015-2016 by Ankit Wagadre (wagadre.ankit@gmail.com) - Copyright : (C) 2015-2016 by Alexander Semke (alexander.semke@web.de) + Copyright : (C) 2015-2019 by Alexander Semke (alexander.semke@web.de) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "DatapickerImageWidget.h" #include "backend/datapicker/DatapickerPoint.h" #include "commonfrontend/widgets/qxtspanslider.h" #include "kdefrontend/GuiTools.h" #include "backend/worksheet/Worksheet.h" #include "backend/worksheet/plots/cartesian/Symbol.h" #include "backend/datapicker/ImageEditor.h" #include #include #include #include #include #include #include #include #include #include #include HistogramView::HistogramView(QWidget* parent, int range) : QGraphicsView(parent), m_scene(new QGraphicsScene()), m_range(range) { setTransform(QTransform()); QRectF pageRect( 0, 0, 1000, 100 ); m_scene->setSceneRect(pageRect); setScene(m_scene); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_lowerSlider = new QGraphicsRectItem(pageRect, nullptr); m_lowerSlider->setPen(QPen(Qt::black, 0.5)); m_lowerSlider->setBrush(Qt::blue); m_lowerSlider->setOpacity(0.2); m_scene->addItem(m_lowerSlider); m_upperSlider = new QGraphicsRectItem(pageRect, nullptr); m_upperSlider->setPen(QPen(Qt::black, 0.5)); m_upperSlider->setBrush(Qt::blue); m_upperSlider->setOpacity(0.2); m_scene->addItem(m_upperSlider); } void HistogramView::setScalePixmap(const QString& file) { // scene rect is 1000*100 where upper 1000*80 is for histogram graph // and lower 1000*20 is for histogram scale QGraphicsPixmapItem* pixmap = new QGraphicsPixmapItem(QPixmap(file).scaled( 1000, 20, Qt::IgnoreAspectRatio), nullptr); pixmap->setZValue(-1); pixmap->setPos(0, 90); m_scene->addItem(pixmap); } void HistogramView::setSpan(int l, int h) { l = l*1000/m_range; h = h*1000/m_range; m_lowerSlider->setPos(QPointF(l - 1000, 0)); m_upperSlider->setPos(QPointF(h, 0)); invalidateScene(sceneRect(), QGraphicsScene::BackgroundLayer); } void HistogramView::resizeEvent(QResizeEvent *event) { fitInView(m_scene->sceneRect(), Qt::IgnoreAspectRatio); QGraphicsView::resizeEvent(event); } void HistogramView::drawBackground(QPainter* painter, const QRectF& rect) { if (!bins) return; painter->save(); painter->setRenderHint(QPainter::Antialiasing, true); int max = 1; for (int i = 0; i <= m_range; i++) if (bins [i] > max) max = bins [i]; // convert y-scale count to log scale so small counts are still visible // scene rect is 1000*100 where upper 1000*80 is for histogram graph // and lower 1000*20 is for histogram scale QPainterPath path(QPointF(0, (log(bins[0])*100/log(max)))); for (int i = 1; i <= m_range; i++) { int x = i*1000/m_range; int y = 80; if ( bins[i] > 1 ) y = 80 - (log(bins[i])*80/log(max)); path.lineTo(QPointF(x, y)); } painter->drawPath(path); invalidateScene(rect, QGraphicsScene::BackgroundLayer); painter->restore(); } DatapickerImageWidget::DatapickerImageWidget(QWidget* parent) : BaseDock(parent), m_image(nullptr) { ui.setupUi(this); m_leName = ui.leName; m_leComment = ui.leComment; ui.leFileName->setClearButtonEnabled(true); ui.bOpen->setIcon( QIcon::fromTheme("document-open") ); ui.leFileName->setCompleter(new QCompleter(new QDirModel, this)); auto* editTabLayout = static_cast(ui.tEdit->layout()); editTabLayout->setContentsMargins(2,2,2,2); editTabLayout->setHorizontalSpacing(2); editTabLayout->setVerticalSpacing(4); ssHue = new QxtSpanSlider(Qt::Horizontal, ui.tEdit); ssHue->setToolTip(i18n("Select the range for the hue.\nEverything outside of this range will be set to white.")); ssHue->setRange(0, 360); editTabLayout->addWidget(ssHue, 3, 2); ssSaturation = new QxtSpanSlider(Qt::Horizontal, ui.tEdit); ssSaturation->setToolTip(i18n("Select the range for the saturation.\nEverything outside of this range will be set to white.")); ssSaturation->setRange(0,100); editTabLayout->addWidget(ssSaturation, 5, 2); ssValue = new QxtSpanSlider(Qt::Horizontal, ui.tEdit); 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.")); ssValue->setRange(0,100); editTabLayout->addWidget(ssValue, 7, 2); ssIntensity = new QxtSpanSlider(Qt::Horizontal, ui.tEdit); ssIntensity->setToolTip(i18n("Select the range for the intensity.\nEverything outside of this range will be set to white.")); ssIntensity->setRange(0, 100); editTabLayout->addWidget(ssIntensity, 9, 2); ssForeground = new QxtSpanSlider(Qt::Horizontal, ui.tEdit); 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.")); ssForeground->setRange(0, 100); editTabLayout->addWidget(ssForeground, 11, 2); ui.cbGraphType->addItem(i18n("Cartesian (x, y)")); ui.cbGraphType->addItem(i18n("Polar (x, y°)")); ui.cbGraphType->addItem(i18n("Polar (x, y(rad))")); ui.cbGraphType->addItem(i18n("Logarithmic (ln(x), y)")); ui.cbGraphType->addItem(i18n("Logarithmic (x, ln(y))")); ui.cbGraphType->addItem(i18n("Ternary (x, y, z)")); ui.lTernaryScale->setHidden(true); ui.sbTernaryScale->setHidden(true); ui.lPositionZ1->setHidden(true); ui.lPositionZ2->setHidden(true); ui.lPositionZ3->setHidden(true); ui.sbPositionZ1->setHidden(true); ui.sbPositionZ2->setHidden(true); ui.sbPositionZ3->setHidden(true); ui.cbPlotImageType->addItem(i18n("No Image")); ui.cbPlotImageType->addItem(i18n("Original Image")); ui.cbPlotImageType->addItem(i18n("Processed Image")); QString valueFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "labplot2/pics/colorchooser/colorchooser_value.xpm"); QString hueFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "labplot2/pics/colorchooser/colorchooser_hue.xpm"); QString saturationFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "labplot2/pics/colorchooser/colorchooser_saturation.xpm"); gvHue = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::Hue)); gvHue->setToolTip(i18n("Select the range for the hue.\nEverything outside of this range will be set to white.")); editTabLayout->addWidget(gvHue, 2, 2); gvHue->setScalePixmap(hueFile); gvSaturation = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::Saturation)); gvSaturation->setToolTip(i18n("Select the range for the saturation.\nEverything outside of this range will be set to white.")); editTabLayout->addWidget(gvSaturation, 4, 2); gvSaturation->setScalePixmap(saturationFile); gvValue = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::Value)); 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.")); editTabLayout->addWidget(gvValue, 6,2); gvValue->setScalePixmap(valueFile); gvIntensity = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::Intensity)); gvIntensity->setToolTip(i18n("Select the range for the intensity.\nEverything outside of this range will be set to white.")); editTabLayout->addWidget(gvIntensity, 8, 2); gvIntensity->setScalePixmap(valueFile); gvForeground = new HistogramView(ui.tEdit, ImageEditor::colorAttributeMax(DatapickerImage::Foreground)); 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.")); editTabLayout->addWidget(gvForeground, 10, 2); gvForeground->setScalePixmap(valueFile); connect( ssIntensity, SIGNAL(spanChanged(int,int)), gvIntensity, SLOT(setSpan(int,int)) ); connect( ssForeground, SIGNAL(spanChanged(int,int)), gvForeground, SLOT(setSpan(int,int)) ); connect( ssHue, SIGNAL(spanChanged(int,int)), gvHue, SLOT(setSpan(int,int)) ); connect( ssSaturation, SIGNAL(spanChanged(int,int)), gvSaturation, SLOT(setSpan(int,int)) ); connect( ssValue, SIGNAL(spanChanged(int,int)), gvValue, SLOT(setSpan(int,int)) ); //SLOTS //general connect(ui.leName, &QLineEdit::textChanged, this, &DatapickerImageWidget::nameChanged); connect(ui.leComment, &QLineEdit::textChanged, this, &DatapickerImageWidget::commentChanged); connect( ui.bOpen, SIGNAL(clicked(bool)), this, SLOT(selectFile())); connect( ui.leFileName, SIGNAL(returnPressed()), this, SLOT(fileNameChanged()) ); connect( ui.leFileName, SIGNAL(textChanged(QString)), this, SLOT(fileNameChanged()) ); // edit image connect( ui.cbPlotImageType, SIGNAL(currentIndexChanged(int)), this, SLOT(plotImageTypeChanged(int)) ); connect( ui.sbRotation, SIGNAL(valueChanged(double)), this, SLOT(rotationChanged(double)) ); connect( ssIntensity, SIGNAL(spanChanged(int,int)), this, SLOT(intensitySpanChanged(int,int)) ); connect( ssForeground, SIGNAL(spanChanged(int,int)), this, SLOT(foregroundSpanChanged(int,int)) ); connect( ssHue, SIGNAL(spanChanged(int,int)), this, SLOT(hueSpanChanged(int,int)) ); connect( ssSaturation, SIGNAL(spanChanged(int,int)), this, SLOT(saturationSpanChanged(int,int)) ); connect( ssValue, SIGNAL(spanChanged(int,int)), this, SLOT(valueSpanChanged(int,int)) ); connect( ui.sbMinSegmentLength, SIGNAL(valueChanged(int)), this, SLOT(minSegmentLengthChanged(int)) ); connect( ui.sbPointSeparation, SIGNAL(valueChanged(int)), this, SLOT(pointSeparationChanged(int)) ); //axis point connect( ui.cbGraphType, SIGNAL(currentIndexChanged(int)), this, SLOT(graphTypeChanged()) ); connect( ui.sbTernaryScale, SIGNAL(valueChanged(double)), this, SLOT(ternaryScaleChanged(double)) ); connect( ui.sbPositionX1, SIGNAL(valueChanged(double)), this, SLOT(logicalPositionChanged()) ); connect( ui.sbPositionY1, SIGNAL(valueChanged(double)), this, SLOT(logicalPositionChanged()) ); connect( ui.sbPositionX2, SIGNAL(valueChanged(double)), this, SLOT(logicalPositionChanged()) ); connect( ui.sbPositionY2, SIGNAL(valueChanged(double)), this, SLOT(logicalPositionChanged()) ); connect( ui.sbPositionX3, SIGNAL(valueChanged(double)), this, SLOT(logicalPositionChanged()) ); connect( ui.sbPositionY3, SIGNAL(valueChanged(double)), this, SLOT(logicalPositionChanged()) ); connect( ui.sbPositionZ1, SIGNAL(valueChanged(double)), this, SLOT(logicalPositionChanged()) ); connect( ui.sbPositionZ2, SIGNAL(valueChanged(double)), this, SLOT(logicalPositionChanged()) ); connect( ui.sbPositionZ3, SIGNAL(valueChanged(double)), this, SLOT(logicalPositionChanged()) ); //SYMBOL connect( ui.cbSymbolStyle, SIGNAL(currentIndexChanged(int)), this, SLOT(pointsStyleChanged(int)) ); connect( ui.sbSymbolSize, SIGNAL(valueChanged(double)), this, SLOT(pointsSizeChanged(double)) ); connect( ui.sbSymbolRotation, SIGNAL(valueChanged(int)), this, SLOT(pointsRotationChanged(int)) ); connect( ui.sbSymbolOpacity, SIGNAL(valueChanged(int)), this, SLOT(pointsOpacityChanged(int)) ); //Filling connect( ui.cbSymbolFillingStyle, SIGNAL(currentIndexChanged(int)), this, SLOT(pointsFillingStyleChanged(int)) ); connect( ui.kcbSymbolFillingColor, SIGNAL(changed(QColor)), this, SLOT(pointsFillingColorChanged(QColor)) ); //border connect( ui.cbSymbolBorderStyle, SIGNAL(currentIndexChanged(int)), this, SLOT(pointsBorderStyleChanged(int)) ); connect( ui.kcbSymbolBorderColor, SIGNAL(changed(QColor)), this, SLOT(pointsBorderColorChanged(QColor)) ); connect( ui.sbSymbolBorderWidth, SIGNAL(valueChanged(double)), this, SLOT(pointsBorderWidthChanged(double)) ); connect( ui.chbSymbolVisible, SIGNAL(clicked(bool)), this, SLOT(pointsVisibilityChanged(bool)) ); init(); } void DatapickerImageWidget::init() { m_initializing = true; GuiTools::updatePenStyles(ui.cbSymbolBorderStyle, Qt::black); QPainter pa; int iconSize = 20; QPixmap pm(iconSize, iconSize); QPen pen(Qt::SolidPattern, 0); ui.cbSymbolStyle->setIconSize(QSize(iconSize, iconSize)); QTransform trafo; trafo.scale(15, 15); //TODO: constant? for (int i = 1; i < 19; ++i) { auto style = (Symbol::Style)i; pm.fill(Qt::transparent); pa.begin(&pm); pa.setPen( pen ); pa.setRenderHint(QPainter::Antialiasing); pa.translate(iconSize/2,iconSize/2); pa.drawPath(trafo.map(Symbol::pathFromStyle(style))); pa.end(); ui.cbSymbolStyle->addItem(QIcon(pm), Symbol::nameFromStyle(style)); } GuiTools::updateBrushStyles(ui.cbSymbolFillingStyle, Qt::black); m_initializing = false; } void DatapickerImageWidget::setImages(QList list) { + m_initializing = true; m_imagesList = list; m_image = list.first(); m_aspect = list.first(); if (list.size() == 1) { ui.lName->setEnabled(true); ui.leName->setEnabled(true); ui.lComment->setEnabled(true); ui.leComment->setEnabled(true); ui.leName->setText(m_image->parentAspect()->name()); ui.leComment->setText(m_image->parentAspect()->comment()); } else { ui.lName->setEnabled(false); ui.leName->setEnabled(false); ui.lComment->setEnabled(false); ui.leComment->setEnabled(false); ui.leName->setText(QString()); ui.leComment->setText(QString()); } this->load(); initConnections(); handleWidgetActions(); updateSymbolWidgets(); + m_initializing = false; } void DatapickerImageWidget::initConnections() { connect( m_image->parentAspect(), SIGNAL(aspectDescriptionChanged(const AbstractAspect*)),this, SLOT(imageDescriptionChanged(const AbstractAspect*))); connect( m_image, SIGNAL(fileNameChanged(QString)), this, SLOT(imageFileNameChanged(QString)) ); connect( m_image, SIGNAL(rotationAngleChanged(float)), this, SLOT(imageRotationAngleChanged(float)) ); connect( m_image, SIGNAL(aspectRemoved(const AbstractAspect*,const AbstractAspect*,const AbstractAspect*)), this,SLOT(updateSymbolWidgets()) ); connect( m_image, SIGNAL(aspectAdded(const AbstractAspect*)), this,SLOT(updateSymbolWidgets()) ); connect( m_image, SIGNAL(axisPointsChanged(DatapickerImage::ReferencePoints)), this, SLOT(imageAxisPointsChanged(DatapickerImage::ReferencePoints)) ); connect( m_image, SIGNAL(settingsChanged(DatapickerImage::EditorSettings)), this, SLOT(imageEditorSettingsChanged(DatapickerImage::EditorSettings)) ); connect( m_image, SIGNAL(minSegmentLengthChanged(int)), this, SLOT(imageMinSegmentLengthChanged(int)) ); connect( m_image, SIGNAL(pointStyleChanged(Symbol::Style)), this, SLOT(symbolStyleChanged(Symbol::Style))); connect( m_image, SIGNAL(pointSizeChanged(qreal)), this, SLOT(symbolSizeChanged(qreal))); connect( m_image, SIGNAL(pointRotationAngleChanged(qreal)), this, SLOT(symbolRotationAngleChanged(qreal))); connect( m_image, SIGNAL(pointOpacityChanged(qreal)), this, SLOT(symbolOpacityChanged(qreal))); connect( m_image, SIGNAL(pointBrushChanged(QBrush)), this, SLOT(symbolBrushChanged(QBrush)) ); connect( m_image, SIGNAL(pointPenChanged(QPen)), this, SLOT(symbolPenChanged(QPen)) ); connect( m_image, SIGNAL(pointVisibilityChanged(bool)), this, SLOT(symbolVisibleChanged(bool)) ); } void DatapickerImageWidget::handleWidgetActions() { QString fileName = ui.leFileName->text().trimmed(); bool b = !fileName.isEmpty(); ui.tEdit->setEnabled(b); ui.cbGraphType->setEnabled(b); ui.sbRotation->setEnabled(b); ui.sbPositionX1->setEnabled(b); ui.sbPositionX2->setEnabled(b); ui.sbPositionX3->setEnabled(b); ui.sbPositionY1->setEnabled(b); ui.sbPositionY2->setEnabled(b); ui.sbPositionY3->setEnabled(b); ui.sbMinSegmentLength->setEnabled(b); ui.sbPointSeparation->setEnabled(b); if (b) { //upload histogram to view gvIntensity->bins = m_image->intensityBins; gvForeground->bins = m_image->foregroundBins; gvHue->bins = m_image->hueBins; gvSaturation->bins = m_image->saturationBins; gvValue->bins = m_image->valueBins; } } //********************************************************** //****** SLOTs for changes triggered in DatapickerImageWidget ******** //********************************************************** //"General"-tab void DatapickerImageWidget::selectFile() { KConfigGroup conf(KSharedConfig::openConfig(), "DatapickerImageWidget"); QString dir = conf.readEntry("LastImageDir", ""); QString formats; for (const QByteArray& format : QImageReader::supportedImageFormats()) { QString f = "*." + QString(format.constData()); formats.isEmpty() ? formats += f : formats += " " + f; } QString path = QFileDialog::getOpenFileName(this, i18n("Select the image file"), dir, i18n("Images (%1)", formats)); if (path.isEmpty()) return; //cancel was clicked in the file-dialog int pos = path.lastIndexOf(QDir::separator()); if (pos != -1) { QString newDir = path.left(pos); if (newDir != dir) conf.writeEntry("LastImageDir", newDir); } ui.leFileName->setText( path ); handleWidgetActions(); for (auto* image : m_imagesList) image->setFileName(path); } void DatapickerImageWidget::fileNameChanged() { if (m_initializing) return; handleWidgetActions(); QString fileName = ui.leFileName->text(); for (auto* image : m_imagesList) image->setFileName(fileName); } void DatapickerImageWidget::graphTypeChanged() { if (m_initializing) return; DatapickerImage::ReferencePoints points = m_image->axisPoints(); points.type = DatapickerImage::GraphType(ui.cbGraphType->currentIndex()); if (points.type != DatapickerImage::Ternary) { ui.lTernaryScale->setHidden(true); ui.sbTernaryScale->setHidden(true); ui.lPositionZ1->setHidden(true); ui.lPositionZ2->setHidden(true); ui.lPositionZ3->setHidden(true); ui.sbPositionZ1->setHidden(true); ui.sbPositionZ2->setHidden(true); ui.sbPositionZ3->setHidden(true); } else { ui.lTernaryScale->setHidden(false); ui.sbTernaryScale->setHidden(false); ui.lPositionZ1->setHidden(false); ui.lPositionZ2->setHidden(false); ui.lPositionZ3->setHidden(false); ui.sbPositionZ1->setHidden(false); ui.sbPositionZ2->setHidden(false); ui.sbPositionZ3->setHidden(false); } for (auto* image : m_imagesList) image->setAxisPoints(points); } void DatapickerImageWidget::ternaryScaleChanged(double value) { if (m_initializing) return; DatapickerImage::ReferencePoints points = m_image->axisPoints(); points.ternaryScale = value; for (auto* image : m_imagesList) image->setAxisPoints(points); } void DatapickerImageWidget::logicalPositionChanged() { if (m_initializing) return; DatapickerImage::ReferencePoints points = m_image->axisPoints(); points.logicalPos[0].setX(ui.sbPositionX1->value()); points.logicalPos[0].setY(ui.sbPositionY1->value()); points.logicalPos[1].setX(ui.sbPositionX2->value()); points.logicalPos[1].setY(ui.sbPositionY2->value()); points.logicalPos[2].setX(ui.sbPositionX3->value()); points.logicalPos[2].setY(ui.sbPositionY3->value()); points.logicalPos[0].setZ(ui.sbPositionZ1->value()); points.logicalPos[1].setZ(ui.sbPositionZ2->value()); points.logicalPos[2].setZ(ui.sbPositionZ3->value()); for (auto* image : m_imagesList) image->setAxisPoints(points); } void DatapickerImageWidget::pointsStyleChanged(int index) { auto style = Symbol::Style(index + 1); //enable/disable the filling options in the GUI depending on the currently selected points. if (style != Symbol::Line && style != Symbol::Cross) { ui.cbSymbolFillingStyle->setEnabled(true); bool noBrush = (Qt::BrushStyle(ui.cbSymbolFillingStyle->currentIndex()) == Qt::NoBrush); ui.kcbSymbolFillingColor->setEnabled(!noBrush); } else { ui.kcbSymbolFillingColor->setEnabled(false); ui.cbSymbolFillingStyle->setEnabled(false); } bool noLine = (Qt::PenStyle(ui.cbSymbolBorderStyle->currentIndex()) == Qt::NoPen); ui.kcbSymbolBorderColor->setEnabled(!noLine); ui.sbSymbolBorderWidth->setEnabled(!noLine); if (m_initializing) return; for (auto* image : m_imagesList) image->setPointStyle(style); } void DatapickerImageWidget::pointsSizeChanged(double value) { if (m_initializing) return; for (auto* image : m_imagesList) image->setPointSize( Worksheet::convertToSceneUnits(value, Worksheet::Point) ); } void DatapickerImageWidget::pointsRotationChanged(int value) { if (m_initializing) return; for (auto* image : m_imagesList) image->setPointRotationAngle(value); } void DatapickerImageWidget::pointsOpacityChanged(int value) { if (m_initializing) return; qreal opacity = (float)value/100.; for (auto* image : m_imagesList) image->setPointOpacity(opacity); } void DatapickerImageWidget::pointsFillingStyleChanged(int index) { auto brushStyle = Qt::BrushStyle(index); ui.kcbSymbolFillingColor->setEnabled(!(brushStyle == Qt::NoBrush)); if (m_initializing) return; QBrush brush; for (auto* image : m_imagesList) { brush = image->pointBrush(); brush.setStyle(brushStyle); image->setPointBrush(brush); } } void DatapickerImageWidget::pointsFillingColorChanged(const QColor& color) { if (m_initializing) return; QBrush brush; for (auto* image : m_imagesList) { brush = image->pointBrush(); brush.setColor(color); image->setPointBrush(brush); } m_initializing = true; GuiTools::updateBrushStyles(ui.cbSymbolFillingStyle, color ); m_initializing = false; } void DatapickerImageWidget::pointsBorderStyleChanged(int index) { auto penStyle = Qt::PenStyle(index); if ( penStyle == Qt::NoPen ) { ui.kcbSymbolBorderColor->setEnabled(false); ui.sbSymbolBorderWidth->setEnabled(false); } else { ui.kcbSymbolBorderColor->setEnabled(true); ui.sbSymbolBorderWidth->setEnabled(true); } if (m_initializing) return; QPen pen; for (auto* image : m_imagesList) { pen = image->pointPen(); pen.setStyle(penStyle); image->setPointPen(pen); } } void DatapickerImageWidget::pointsBorderColorChanged(const QColor& color) { if (m_initializing) return; QPen pen; for (auto* image : m_imagesList) { pen = image->pointPen(); pen.setColor(color); image->setPointPen(pen); } m_initializing = true; GuiTools::updatePenStyles(ui.cbSymbolBorderStyle, color); m_initializing = false; } void DatapickerImageWidget::pointsBorderWidthChanged(double value) { if (m_initializing) return; QPen pen; for (auto* image : m_imagesList) { pen = image->pointPen(); pen.setWidthF( Worksheet::convertToSceneUnits(value, Worksheet::Point) ); image->setPointPen(pen); } } void DatapickerImageWidget::pointsVisibilityChanged(bool state) { if (m_initializing) return; for (auto* image : m_imagesList) image->setPointVisibility(state); } void DatapickerImageWidget::intensitySpanChanged(int lowerLimit, int upperLimit) { if (m_initializing) return; DatapickerImage::EditorSettings settings = m_image->settings(); settings.intensityThresholdHigh = upperLimit; settings.intensityThresholdLow = lowerLimit; for (auto* image : m_imagesList) image->setSettings(settings); } void DatapickerImageWidget::foregroundSpanChanged(int lowerLimit, int upperLimit) { if (m_initializing) return; DatapickerImage::EditorSettings settings = m_image->settings(); settings.foregroundThresholdHigh = upperLimit; settings.foregroundThresholdLow = lowerLimit; for (auto* image : m_imagesList) image->setSettings(settings); } void DatapickerImageWidget::hueSpanChanged(int lowerLimit, int upperLimit) { if (m_initializing) return; DatapickerImage::EditorSettings settings = m_image->settings(); settings.hueThresholdHigh = upperLimit; settings.hueThresholdLow = lowerLimit; for (auto* image : m_imagesList) image->setSettings(settings); } void DatapickerImageWidget::saturationSpanChanged(int lowerLimit, int upperLimit) { if (m_initializing) return; DatapickerImage::EditorSettings settings = m_image->settings(); settings.saturationThresholdHigh = upperLimit; settings.saturationThresholdLow = lowerLimit; for (auto* image : m_imagesList) image->setSettings(settings); } void DatapickerImageWidget::valueSpanChanged(int lowerLimit, int upperLimit) { if (m_initializing) return; DatapickerImage::EditorSettings settings = m_image->settings(); settings.valueThresholdHigh = upperLimit; settings.valueThresholdLow = lowerLimit; for (auto* image : m_imagesList) image->setSettings(settings); } void DatapickerImageWidget::plotImageTypeChanged(int index) { if (m_initializing) return; for (auto* image : m_imagesList) image->setPlotImageType(DatapickerImage::PlotImageType(index)); } void DatapickerImageWidget::rotationChanged(double value) { if (m_initializing) return; for (auto* image : m_imagesList) image->setRotationAngle(value); } void DatapickerImageWidget::minSegmentLengthChanged(int value) { if (m_initializing) return; for (auto* image : m_imagesList) image->setminSegmentLength(value); } void DatapickerImageWidget::pointSeparationChanged(int value) { if (m_initializing) return; for (auto* image : m_imagesList) image->setPointSeparation(value); } //******************************************************************* //******** SLOTs for changes triggered in DatapickerImage *********** //******************************************************************* /*! * called when the name or comment of image's parent (datapicker) was changed. */ void DatapickerImageWidget::imageDescriptionChanged(const AbstractAspect* aspect) { if (m_image->parentAspect() != aspect) return; m_initializing = true; if (aspect->name() != ui.leName->text()) { ui.leName->setText(aspect->name()); } else if (aspect->comment() != ui.leComment->text()) { ui.leComment->setText(aspect->comment()); } m_initializing = false; } void DatapickerImageWidget::imageFileNameChanged(const QString& name) { m_initializing = true; ui.leFileName->setText(name); m_initializing = false; } void DatapickerImageWidget::imageRotationAngleChanged(float angle) { m_initializing = true; ui.sbRotation->setValue(angle); m_initializing = false; } void DatapickerImageWidget::imageAxisPointsChanged(const DatapickerImage::ReferencePoints& axisPoints) { m_initializing = true; ui.cbGraphType->setCurrentIndex((int) axisPoints.type); ui.sbTernaryScale->setValue(axisPoints.ternaryScale); ui.sbPositionX1->setValue(axisPoints.logicalPos[0].x()); ui.sbPositionY1->setValue(axisPoints.logicalPos[0].y()); ui.sbPositionX2->setValue(axisPoints.logicalPos[1].x()); ui.sbPositionY2->setValue(axisPoints.logicalPos[1].y()); ui.sbPositionX3->setValue(axisPoints.logicalPos[2].x()); ui.sbPositionY3->setValue(axisPoints.logicalPos[2].y()); ui.sbPositionZ1->setValue(axisPoints.logicalPos[0].z()); ui.sbPositionZ2->setValue(axisPoints.logicalPos[1].z()); ui.sbPositionZ3->setValue(axisPoints.logicalPos[2].z()); m_initializing = false; } void DatapickerImageWidget::imageEditorSettingsChanged(const DatapickerImage::EditorSettings& settings) { m_initializing = true; ssIntensity->setSpan(settings.intensityThresholdLow, settings.intensityThresholdHigh); ssForeground->setSpan(settings.foregroundThresholdLow, settings.foregroundThresholdHigh); ssHue->setSpan(settings.hueThresholdLow, settings.hueThresholdHigh); ssSaturation->setSpan(settings.saturationThresholdLow, settings.saturationThresholdHigh); ssValue->setSpan(settings.valueThresholdLow, settings.valueThresholdHigh); gvIntensity->setSpan(settings.intensityThresholdLow, settings.intensityThresholdHigh); gvForeground->setSpan(settings.foregroundThresholdLow, settings.foregroundThresholdHigh); gvHue->setSpan(settings.hueThresholdLow, settings.hueThresholdHigh); gvSaturation->setSpan(settings.saturationThresholdLow, settings.saturationThresholdHigh); gvValue->setSpan(settings.valueThresholdLow, settings.valueThresholdHigh); m_initializing = false; } void DatapickerImageWidget::imageMinSegmentLengthChanged(const int value) { m_initializing = true; ui.sbMinSegmentLength->setValue(value); m_initializing = false; } void DatapickerImageWidget::updateSymbolWidgets() { int pointCount = m_image->childCount(AbstractAspect::IncludeHidden); if (pointCount) ui.tSymbol->setEnabled(true); else ui.tSymbol->setEnabled(false); } void DatapickerImageWidget::symbolStyleChanged(Symbol::Style style) { m_initializing = true; ui.cbSymbolStyle->setCurrentIndex((int)style - 1); m_initializing = false; } void DatapickerImageWidget::symbolSizeChanged(qreal size) { m_initializing = true; ui.sbSymbolSize->setValue( Worksheet::convertFromSceneUnits(size, Worksheet::Point) ); m_initializing = false; } void DatapickerImageWidget::symbolRotationAngleChanged(qreal angle) { m_initializing = true; ui.sbSymbolRotation->setValue(round(angle)); m_initializing = false; } void DatapickerImageWidget::symbolOpacityChanged(qreal opacity) { m_initializing = true; ui.sbSymbolOpacity->setValue( round(opacity*100.0) ); m_initializing = false; } void DatapickerImageWidget::symbolBrushChanged(const QBrush& brush) { m_initializing = true; ui.cbSymbolFillingStyle->setCurrentIndex((int) brush.style()); ui.kcbSymbolFillingColor->setColor(brush.color()); GuiTools::updateBrushStyles(ui.cbSymbolFillingStyle, brush.color()); m_initializing = false; } void DatapickerImageWidget::symbolPenChanged(const QPen& pen) { m_initializing = true; ui.cbSymbolBorderStyle->setCurrentIndex( (int) pen.style()); ui.kcbSymbolBorderColor->setColor( pen.color()); GuiTools::updatePenStyles(ui.cbSymbolBorderStyle, pen.color()); ui.sbSymbolBorderWidth->setValue( Worksheet::convertFromSceneUnits(pen.widthF(), Worksheet::Point)); m_initializing = false; } void DatapickerImageWidget::symbolVisibleChanged(bool on) { m_initializing = true; ui.chbSymbolVisible->setChecked(on); m_initializing = false; } //********************************************************** //******************** SETTINGS **************************** //********************************************************** void DatapickerImageWidget::load() { if (!m_image) return; m_initializing = true; ui.leFileName->setText( m_image->fileName() ); ui.cbGraphType->setCurrentIndex((int) m_image->axisPoints().type); ui.sbTernaryScale->setValue(m_image->axisPoints().ternaryScale); ui.sbPositionX1->setValue(m_image->axisPoints().logicalPos[0].x()); ui.sbPositionY1->setValue(m_image->axisPoints().logicalPos[0].y()); ui.sbPositionX2->setValue(m_image->axisPoints().logicalPos[1].x()); ui.sbPositionY2->setValue(m_image->axisPoints().logicalPos[1].y()); ui.sbPositionX3->setValue(m_image->axisPoints().logicalPos[2].x()); ui.sbPositionY3->setValue(m_image->axisPoints().logicalPos[2].y()); ui.sbPositionZ1->setValue(m_image->axisPoints().logicalPos[0].z()); ui.sbPositionZ2->setValue(m_image->axisPoints().logicalPos[1].z()); ui.sbPositionZ3->setValue(m_image->axisPoints().logicalPos[2].z()); ui.cbPlotImageType->setCurrentIndex((int) m_image->plotImageType()); ssIntensity->setSpan(m_image->settings().intensityThresholdLow, m_image->settings().intensityThresholdHigh); ssForeground->setSpan(m_image->settings().foregroundThresholdLow, m_image->settings().foregroundThresholdHigh); ssHue->setSpan(m_image->settings().hueThresholdLow, m_image->settings().hueThresholdHigh); ssSaturation->setSpan(m_image->settings().saturationThresholdLow, m_image->settings().saturationThresholdHigh); ssValue->setSpan(m_image->settings().valueThresholdLow, m_image->settings().valueThresholdHigh); gvIntensity->setSpan(m_image->settings().intensityThresholdLow, m_image->settings().intensityThresholdHigh); gvForeground->setSpan(m_image->settings().foregroundThresholdLow, m_image->settings().foregroundThresholdHigh); gvHue->setSpan(m_image->settings().hueThresholdLow, m_image->settings().hueThresholdHigh); gvSaturation->setSpan(m_image->settings().saturationThresholdLow, m_image->settings().saturationThresholdHigh); gvValue->setSpan(m_image->settings().valueThresholdLow, m_image->settings().valueThresholdHigh); ui.sbPointSeparation->setValue(m_image->pointSeparation()); ui.sbMinSegmentLength->setValue(m_image->minSegmentLength()); ui.cbSymbolStyle->setCurrentIndex( (int)m_image->pointStyle() - 1 ); ui.sbSymbolSize->setValue( Worksheet::convertFromSceneUnits(m_image->pointSize(), Worksheet::Point) ); ui.sbSymbolRotation->setValue( m_image->pointRotationAngle() ); ui.sbSymbolOpacity->setValue( round(m_image->pointOpacity()*100.0) ); ui.cbSymbolFillingStyle->setCurrentIndex( (int) m_image->pointBrush().style() ); ui.kcbSymbolFillingColor->setColor( m_image->pointBrush().color() ); ui.cbSymbolBorderStyle->setCurrentIndex( (int) m_image->pointPen().style() ); ui.kcbSymbolBorderColor->setColor( m_image->pointPen().color() ); ui.sbSymbolBorderWidth->setValue( Worksheet::convertFromSceneUnits(m_image->pointPen().widthF(), Worksheet::Point) ); ui.chbSymbolVisible->setChecked( m_image->pointVisibility() ); m_initializing = false; } diff --git a/src/kdefrontend/widgets/DatapickerImageWidget.h b/src/kdefrontend/widgets/DatapickerImageWidget.h index 08fc22eb6..b2335b7e5 100644 --- a/src/kdefrontend/widgets/DatapickerImageWidget.h +++ b/src/kdefrontend/widgets/DatapickerImageWidget.h @@ -1,143 +1,142 @@ /*************************************************************************** File : DatapickerImageWidget.h Project : LabPlot Description : widget for datapicker properties -------------------------------------------------------------------- Copyright : (C) 2015 by Ankit Wagadre (wagadre.ankit@gmail.com) Copyright : (C) 2015 by Alexander Semke (alexander.semke@web.de) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #ifndef DATAPICKERIMAGEWIDGET_H #define DATAPICKERIMAGEWIDGET_H #include #include "ui_datapickerimagewidget.h" #include "backend/datapicker/DatapickerImage.h" #include "kdefrontend/dockwidgets/BaseDock.h" class QxtSpanSlider; class HistogramView : public QGraphicsView { Q_OBJECT public: explicit HistogramView(QWidget*, int); void setScalePixmap(const QString&); int *bins{nullptr}; public slots: void setSpan(int, int); private: void resizeEvent(QResizeEvent *event) override; void drawBackground(QPainter*, const QRectF&) override; QGraphicsRectItem* m_lowerSlider; QGraphicsRectItem* m_upperSlider; QGraphicsScene* m_scene; int m_range; }; class DatapickerImageWidget : public BaseDock { Q_OBJECT public: explicit DatapickerImageWidget(QWidget*); void setImages(QList); void load(); private: Ui::DatapickerImageWidget ui; void init(); void initConnections(); DatapickerImage* m_image; QList m_imagesList; - bool m_initializing; QxtSpanSlider* ssIntensity; QxtSpanSlider* ssForeground; QxtSpanSlider* ssHue; QxtSpanSlider* ssSaturation; QxtSpanSlider* ssValue; HistogramView* gvIntensity; HistogramView* gvForeground; HistogramView* gvHue; HistogramView* gvSaturation; HistogramView* gvValue; private slots: //SLOTs for changes triggered in DatapickerImageWidget //"General"-tab void fileNameChanged(); void selectFile(); void plotImageTypeChanged(int); //"Edit image"-tab void rotationChanged(double); void intensitySpanChanged(int, int); void foregroundSpanChanged(int, int); void hueSpanChanged(int, int); void saturationSpanChanged(int, int); void valueSpanChanged(int, int); void minSegmentLengthChanged(int); void pointSeparationChanged(int); void graphTypeChanged(); void ternaryScaleChanged(double); void logicalPositionChanged(); //symbol propeties void pointsStyleChanged(int); void pointsSizeChanged(double); void pointsRotationChanged(int); void pointsOpacityChanged(int); void pointsFillingStyleChanged(int); void pointsFillingColorChanged(const QColor&); void pointsBorderStyleChanged(int); void pointsBorderColorChanged(const QColor&); void pointsBorderWidthChanged(double); void pointsVisibilityChanged(bool); //SLOTs for changes triggered in DatapickerImageWidget void imageDescriptionChanged(const AbstractAspect*); void imageFileNameChanged(const QString&); void imageRotationAngleChanged(float); void imageAxisPointsChanged(const DatapickerImage::ReferencePoints&); void imageEditorSettingsChanged(const DatapickerImage::EditorSettings&); void imageMinSegmentLengthChanged(const int); void updateSymbolWidgets(); void handleWidgetActions(); //symbol void symbolStyleChanged(Symbol::Style); void symbolSizeChanged(qreal); void symbolRotationAngleChanged(qreal); void symbolOpacityChanged(qreal); void symbolBrushChanged(const QBrush&); void symbolPenChanged(const QPen&); void symbolVisibleChanged(bool); }; #endif //DATAPICKERIMAGEWIDGET_H