VisualizationGraphWidget.cpp
165 lines
| 5.7 KiB
| text/x-c
|
CppLexer
r93 | #include "Visualization/VisualizationGraphWidget.h" | |||
Alexandre Leroux
|
r171 | #include "Visualization/GraphPlottablesFactory.h" | ||
Alexandre Leroux
|
r192 | #include "Visualization/IVisualizationWidgetVisitor.h" | ||
r58 | #include "ui_VisualizationGraphWidget.h" | |||
r219 | #include <Data/ArrayData.h> | |||
#include <Data/IDataSeries.h> | ||||
#include <SqpApplication.h> | ||||
r111 | #include <Variable/Variable.h> | |||
r219 | #include <Variable/VariableController.h> | |||
r111 | #include <unordered_map> | |||
Alexandre Leroux
|
r204 | Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget") | ||
Alexandre Leroux
|
r166 | namespace { | ||
/// Key pressed to enable zoom on horizontal axis | ||||
const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier; | ||||
/// Key pressed to enable zoom on vertical axis | ||||
const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier; | ||||
} // namespace | ||||
r111 | struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate { | |||
// 1 variable -> n qcpplot | ||||
r219 | std::unordered_multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> | |||
m_VariableToPlotMultiMap; | ||||
r111 | }; | |||
Alexandre Leroux
|
r191 | VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent) | ||
r113 | : QWidget{parent}, | |||
ui{new Ui::VisualizationGraphWidget}, | ||||
r111 | impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()} | |||
r58 | { | |||
ui->setupUi(this); | ||||
Alexandre Leroux
|
r165 | |||
Alexandre Leroux
|
r182 | // qcpplot title | ||
ui->widget->plotLayout()->insertRow(0); | ||||
ui->widget->plotLayout()->addElement(0, 0, new QCPTextElement{ui->widget, name}); | ||||
Alexandre Leroux
|
r165 | // Set qcpplot properties : | ||
Alexandre Leroux
|
r167 | // - Drag (on x-axis) and zoom are enabled | ||
Alexandre Leroux
|
r166 | // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation | ||
Alexandre Leroux
|
r165 | ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); | ||
Alexandre Leroux
|
r167 | ui->widget->axisRect()->setRangeDrag(Qt::Horizontal); | ||
Alexandre Leroux
|
r166 | connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel); | ||
Alexandre Leroux
|
r211 | connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>( | ||
&QCPAxis::rangeChanged), | ||||
this, &VisualizationGraphWidget::onRangeChanged); | ||||
r58 | } | |||
Alexandre Leroux
|
r211 | |||
r58 | VisualizationGraphWidget::~VisualizationGraphWidget() | |||
{ | ||||
delete ui; | ||||
} | ||||
r111 | ||||
void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable) | ||||
{ | ||||
Alexandre Leroux
|
r171 | // Uses delegate to create the qcpplot components according to the variable | ||
Alexandre Leroux
|
r174 | auto createdPlottables = GraphPlottablesFactory::create(variable, *ui->widget); | ||
Alexandre Leroux
|
r171 | |||
for (auto createdPlottable : qAsConst(createdPlottables)) { | ||||
r219 | impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable}); | |||
Alexandre Leroux
|
r171 | } | ||
r219 | ||||
Alexandre Leroux
|
r221 | connect(variable.get(), SIGNAL(dataCacheUpdated()), this, SLOT(onDataCacheVariableUpdated())); | ||
r111 | } | |||
Alexandre Leroux
|
r192 | void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor) | ||
r111 | { | |||
Alexandre Leroux
|
r193 | if (visitor) { | ||
visitor->visit(this); | ||||
} | ||||
Alexandre Leroux
|
r204 | else { | ||
qCCritical(LOG_VisualizationGraphWidget()) | ||||
<< tr("Can't visit widget : the visitor is null"); | ||||
} | ||||
r111 | } | |||
Alexandre Leroux
|
r194 | bool VisualizationGraphWidget::canDrop(const Variable &variable) const | ||
{ | ||||
/// @todo : for the moment, a graph can always accomodate a variable | ||||
Q_UNUSED(variable); | ||||
return true; | ||||
} | ||||
r111 | void VisualizationGraphWidget::close() | |||
{ | ||||
// The main view cannot be directly closed. | ||||
return; | ||||
} | ||||
r112 | QString VisualizationGraphWidget::name() const | |||
r111 | { | |||
Alexandre Leroux
|
r182 | if (auto title = dynamic_cast<QCPTextElement *>(ui->widget->plotLayout()->elementAt(0))) { | ||
return title->text(); | ||||
} | ||||
else { | ||||
return QString{}; | ||||
} | ||||
r111 | } | |||
Alexandre Leroux
|
r166 | |||
Alexandre Leroux
|
r211 | void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2) | ||
{ | ||||
r219 | ||||
qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged"); | ||||
for (auto it = impl->m_VariableToPlotMultiMap.cbegin(); | ||||
it != impl->m_VariableToPlotMultiMap.cend(); ++it) { | ||||
auto variable = it->first; | ||||
auto tolerance = 0.1 * (t2.upper - t2.lower); | ||||
auto dateTime = SqpDateTime{t2.lower - tolerance, t2.upper + tolerance}; | ||||
qCInfo(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged") | ||||
<< variable->dataSeries()->xAxisData()->size(); | ||||
if (!variable->contains(dateTime)) { | ||||
sqpApp->variableController().requestDataLoading(variable, dateTime); | ||||
} | ||||
Alexandre Leroux
|
r211 | } | ||
} | ||||
Alexandre Leroux
|
r166 | void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept | ||
{ | ||||
auto zoomOrientations = QFlags<Qt::Orientation>{}; | ||||
// Lambda that enables a zoom orientation if the key modifier related to this orientation has | ||||
// been pressed | ||||
auto enableOrientation | ||||
= [&zoomOrientations, event](const auto &orientation, const auto &modifier) { | ||||
auto orientationEnabled = event->modifiers().testFlag(modifier); | ||||
zoomOrientations.setFlag(orientation, orientationEnabled); | ||||
}; | ||||
enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER); | ||||
enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER); | ||||
ui->widget->axisRect()->setRangeZoom(zoomOrientations); | ||||
} | ||||
r219 | ||||
void VisualizationGraphWidget::onDataCacheVariableUpdated() | ||||
{ | ||||
for (auto it = impl->m_VariableToPlotMultiMap.cbegin(); | ||||
it != impl->m_VariableToPlotMultiMap.cend(); ++it) { | ||||
auto variable = it->first; | ||||
GraphPlottablesFactory::updateData(QVector<QCPAbstractPlottable *>{} << it->second, | ||||
variable->dataSeries(), variable->dateTime()); | ||||
} | ||||
} | ||||
void VisualizationGraphWidget::updateDisplay(std::shared_ptr<Variable> variable) | ||||
{ | ||||
auto abstractPlotableItPair = impl->m_VariableToPlotMultiMap.equal_range(variable); | ||||
auto abstractPlotableVect = QVector<QCPAbstractPlottable *>{}; | ||||
for (auto it = abstractPlotableItPair.first; it != abstractPlotableItPair.second; ++it) { | ||||
abstractPlotableVect.push_back(it->second); | ||||
} | ||||
GraphPlottablesFactory::updateData(abstractPlotableVect, variable->dataSeries(), | ||||
variable->dateTime()); | ||||
} | ||||