#include "pch.h" #include "GraphPlott.h" #include #include #include #include #include #include #include "HoverButton.h" #include #include GraphPlott::GraphPlott(QWidget* parent, bool showSettingsButton, bool showInformationButton, bool showGridButton) : Plott(parent) { QVBoxLayout* layoutOuter = new QVBoxLayout(this); buttonPanel = new QHBoxLayout(); dialog = new GraphViewSettingDialog(this, "Settings"); this->setMouseTracking(true); buttonPanel->insertStretch(0); displayLabel = new QLabel(""); buttonPanel->addWidget(displayLabel); HoverButton* frameButton = new HoverButton(); frameButton->setMinimumSize(20, 20); frameButton->setMaximumSize(20, 20); frameButton->setIcon(QIcon(":/metavis/Resources/frame.svg")); frameButton->setHoveredIcon(QIcon(":/metavis/Resources/frame_hovered.svg")); frameButton->setAttribute(Qt::WA_TranslucentBackground); frameButton->setStyleSheet(frameButton->styleSheet() + "border: none;"); frameButton->setToolTip("Frame"); buttonPanel->addWidget(frameButton); connect(frameButton, &QPushButton::released, this, &GraphPlott::frameGraphInView); if (showGridButton) { HoverButton* gridButton = new HoverButton(); gridButton->setMinimumSize(20, 20); gridButton->setMaximumSize(20, 20); gridButton->setIcon(QIcon(":/metavis/Resources/gridIcon.svg")); gridButton->setHoveredIcon(QIcon(":/metavis/Resources/gridIcon_hovered.svg")); gridButton->setAttribute(Qt::WA_TranslucentBackground); gridButton->setStyleSheet(gridButton->styleSheet() + "border: none;"); gridButton->setToolTip("Toggle Grid"); buttonPanel->addWidget(gridButton); connect(gridButton, &QPushButton::released, this, [this]() {this->enableGrid = !this->enableGrid; update(); }); } if (showInformationButton) { informationButton->setMinimumSize(20, 20); informationButton->setMaximumSize(20, 20); informationButton->setIcon(QIcon(":/metavis/Resources/information_icon.svg")); informationButton->setHoveredIcon(QIcon(":/metavis/Resources/information_icon_hovered.svg")); informationButton->setAttribute(Qt::WA_TranslucentBackground); informationButton->setStyleSheet(informationButton->styleSheet() + "border: none;"); informationButton->setToolTip("Information"); connect(informationButton, &QPushButton::released, this, &GraphPlott::showInformation); buttonPanel->addWidget(informationButton); } if (showSettingsButton) { HoverButton* settingsButton = new HoverButton(); settingsButton->setMinimumSize(20, 20); settingsButton->setMaximumSize(20, 20); settingsButton->setIcon(QIcon(":/metavis/Resources/settingIcon.svg")); settingsButton->setHoveredIcon(QIcon(":/metavis/Resources/settingIcon_hovered.svg")); settingsButton->setAttribute(Qt::WA_TranslucentBackground); settingsButton->setStyleSheet(settingsButton->styleSheet() + "border: none;"); settingsButton->setToolTip("Settings"); buttonPanel->addWidget(settingsButton); connect(settingsButton, &QPushButton::released, dialog, &GraphViewSettingDialog::openDialog); } buttonPanel->setSpacing(0); buttonPanel->setContentsMargins(0, 0, 0, 0); layoutOuter->addLayout(buttonPanel); layoutOuter->insertStretch(1); layoutOuter->setContentsMargins(0, 0, 0, 0); //QMenu selectMenu->addAction(displayAreaAction); selectMenu->addAction(scratchpadAction); displayAreaAction->setShortcut(QKeySequence(Qt::CTRL)); scratchpadAction->setShortcut(QKeySequence(Qt::ALT)); scratchpadAction->setEnabled(false); //setUpTimer timer->setSingleShot(true); connect(timer, &QTimer::timeout, this, &GraphPlott::searchForPointUnderCursor); } GraphPlott::~GraphPlott() { } void GraphPlott::addSeries(std::vector* line, std::string runName, QString description, QColor color, GraphPlottSeries::SeriesType type) { if (line->empty()) { qDebug() << "Series is empty!"; return; } GraphPlottSeries lgs; lgs.runName = runName; lgs.description = description; lgs.data = line; lgs.type = type; lgs.color = color; //set min max x y auto pairX = std::minmax_element(lgs.data->begin(), lgs.data->end(), [](const GraphDataPoint& a, const GraphDataPoint& b) -> bool {return a.x < b.x; }); lgs.xMin = pairX.first->x; lgs.xMax = pairX.second->x; auto pairY = std::minmax_element(lgs.data->begin(), lgs.data->end(), [](const GraphDataPoint& a, const GraphDataPoint& b) -> bool {return a.y < b.y; }); lgs.yMin = pairY.first->y; lgs.yMax = pairY.second->y; seriesVec.push_back(lgs); } void GraphPlott::removeRunData(RunData* run) { //Remove all series with this rundata auto iter = std::remove_if(seriesVec.begin(), seriesVec.end(), [run](GraphPlottSeries& series) {return (run->name == series.runName); }); seriesVec.erase(iter, seriesVec.end()); displayLabel->setText(""); } void GraphPlott::removeAll() { seriesVec.clear(); } void GraphPlott::setInformation(QString information) { this->informationButtonString = information; popupWidget->setInformation(information); } std::vector& GraphPlott::getSeriesVector() { return seriesVec; } void GraphPlott::resetToDefaultWindow() { frameGraphInView(); } void GraphPlott::frameGraphInView() { if(seriesVec.empty()) return; window.xMin = std::min_element(std::begin(seriesVec), std::end(seriesVec), [](const GraphPlottSeries& a, const GraphPlottSeries& b) -> bool {return a.xMin < b.xMin; })->xMin; window.xMax = std::max_element(std::begin(seriesVec), std::end(seriesVec), [](const GraphPlottSeries& a, const GraphPlottSeries& b) -> bool {return a.xMax < b.xMax; })->xMax; window.yMin = std::min_element(std::begin(seriesVec), std::end(seriesVec), [](const GraphPlottSeries& a, const GraphPlottSeries& b) -> bool {return a.yMin < b.yMin; })->yMin; window.yMax = std::max_element(std::begin(seriesVec), std::end(seriesVec), [](const GraphPlottSeries& a, const GraphPlottSeries& b) -> bool {return a.yMax < b.yMax; })->yMax; window.ZoomOut(0.05); update(); } void GraphPlott::setDisplayLabel(QString file) { displayLabel->setText("\"" + file + "\" "); } void GraphPlott::setScratchpad(Scratchpad* pad) { this->pad = pad; scratchpadAction->setEnabled(true); } void GraphPlott::showInformation() { QPoint position = QCursor::pos(); popupWidget->setInformation(informationButtonString + graphplottInformation); popupWidget->width(); QRect screen = QApplication::desktop()->screenGeometry(); if (position.x() + popupWidget->width() > screen.width()) { popupWidget->move(screen.width() - popupWidget->width(), position.y()); } else { popupWidget->move(position.x(), position.y()); } popupWidget->show(); } void GraphPlott::drawData(QPainter& painter) { QPen linePen; QRect graphDisplayRect = getDisplayRect(); QPointF translation(graphDisplayRect.left(), graphDisplayRect.top()); double stregth_factorX = graphDisplayRect.width() / std::abs(window.xMax - window.xMin); double stregth_factorY = graphDisplayRect.height() / std::abs(window.yMax - window.yMin); for (const GraphPlottSeries& graphSeries : seriesVec) { if (!graphSeries.data) { qDebug() << "Pointer to nothing pls help"; } if (graphSeries.data->empty() || graphSeries.hide) continue; linePen.setColor(graphSeries.color); if (graphSeries.type == GraphPlottSeries::SeriesType::Line || graphSeries.type == GraphPlottSeries::SeriesType::LineDot) { linePen.setWidth(graphSeries.lineWidth/* + ((&graphSeries == highlightSeries) ? 5 : 0)*/); painter.setPen(linePen); QPainterPath painterPath; QPointF oldpoint = graphSeries.data->at(0).toQPointF(); painterPath.moveTo(transformGraphToView(oldpoint, stregth_factorX, stregth_factorY, translation)); for (int i = 1; i < graphSeries.data->size(); i++) { QPointF newpoint = graphSeries.data->at(i).toQPointF(); bool inBoundOldPoint = window.inBoundX(oldpoint); bool inBoundNewPoint = window.inBoundX(newpoint); if (!inBoundOldPoint && !inBoundNewPoint) { } else if (!inBoundOldPoint && inBoundNewPoint) { painterPath.moveTo(transformGraphToView(oldpoint, stregth_factorX, stregth_factorY, translation)); painterPath.lineTo(transformGraphToView(newpoint, stregth_factorX, stregth_factorY, translation)); } else if (inBoundOldPoint && inBoundNewPoint) { painterPath.lineTo(transformGraphToView(newpoint, stregth_factorX, stregth_factorY, translation)); } else if (inBoundOldPoint && !inBoundNewPoint) { painterPath.lineTo(transformGraphToView(newpoint, stregth_factorX, stregth_factorY, translation)); break; } oldpoint = newpoint; } //painterPath.translate(translation); painter.drawPath(painterPath); } if (graphSeries.type == GraphPlottSeries::SeriesType::Dot || graphSeries.type == GraphPlottSeries::SeriesType::LineDot) { linePen.setWidth(2); linePen.setColor(Qt::transparent); painter.setPen(linePen); painter.setBrush(graphSeries.color); const bool useColor = graphSeries.useDataPointColor; for (auto data : *graphSeries.data) { if (useColor){ linePen.setColor(data.color); painter.setPen(linePen); painter.setBrush(data.color); } if (window.inBound(data.toQPointF())) { painter.drawEllipse(transformGraphToView(data.toQPointF(), stregth_factorX, stregth_factorY, translation), graphSeries.circleRadius, graphSeries.circleRadius); } } painter.setBrush(Qt::BrushStyle::NoBrush); } } } void GraphPlott::mouseMoveEvent(QMouseEvent* event) { Plott::mouseMoveEvent(event); lastPosition = event->pos(); timer->start(stayStillTimeMS); QToolTip::hideText(); } void GraphPlott::handleSelectedWindow(VisibleWindow& window, QMouseEvent* event) { if (event->modifiers() & Qt::ControlModifier) { setWindow(window); } else if (event->modifiers() & Qt::AltModifier) { addPointsInWindowToScratchPad(window); } else { QAction* used = selectMenu->exec(this->mapToGlobal(event->pos())); if(used == displayAreaAction){ setWindow(window); } else if (used == scratchpadAction) { addPointsInWindowToScratchPad(window); } } } void GraphPlott::searchForPointUnderCursor() { //check if mouse stayed still QPoint globalPosition = QCursor::pos(); QPointF pos = this->mapFromGlobal(globalPosition); if (pos != lastPosition) { return; } if (seriesVec.empty() || seriesVec[0].data->empty()) { return; } QRect graphDisplayRect = getDisplayRect(); QPointF translation(graphDisplayRect.left(), graphDisplayRect.top()); double stregth_factorX = graphDisplayRect.width() / std::abs(window.xMax - window.xMin); double stregth_factorY = graphDisplayRect.height() / std::abs(window.yMax - window.yMin); const GraphDataPoint* min = &seriesVec[0].data->at(0); double minSqaredDistance = sqaredDistance(transformGraphToView(min->toQPointF(), stregth_factorX, stregth_factorY, translation), pos); std::vector::iterator actualBestSeries = seriesVec.begin(); for (auto seriesIter = seriesVec.begin(); seriesIter != seriesVec.end(); seriesIter++) { for (const GraphDataPoint& point : *seriesIter->data) { double distance = sqaredDistance(transformGraphToView(point.toQPointF(), stregth_factorX, stregth_factorY, translation), pos); if (distance <= minSqaredDistance) { minSqaredDistance = distance; min = &point; actualBestSeries = seriesIter; } } } if (minSqaredDistance <= 20) { QPointF pointInWidget = transformGraphToView(min->toQPointF(), stregth_factorX, stregth_factorY, translation); QToolTip::showText(this->mapToGlobal(QPoint(pointInWidget.x(), pointInWidget.y())) - QPoint(0, 35), actualBestSeries->description); } } double GraphPlott::sqaredDistance(const QPointF& a, const QPointF& b) { return std::pow(a.x() - b.x(), 2) + std::pow(a.y() - b.y(), 2); } void GraphPlott::addPointsInWindowToScratchPad(VisibleWindow& window) { if (!pad) { qDebug() << "NoPad"; return; } for (auto seriesIter = seriesVec.begin(); seriesIter != seriesVec.end(); seriesIter++) { if (seriesIter->hide) continue; for (const GraphDataPoint& point : *seriesIter->data) { if (window.inBound(point.toQPointF()) && point.existLink()) { pad->addPoint(*point.orginalPoint); } } } } void GraphPlott::keyPressEvent(QKeyEvent* event) { Plott::keyPressEvent(event); switch (event->key()) { case Qt::Key_T: frameGraphInView(); break; default: break; } }