Implement multiplot widget (##33)

This commit is contained in:
Alex Spataru 2021-10-06 16:16:01 -05:00
parent 410ed97eb3
commit 4779f704bb
5 changed files with 204 additions and 6 deletions

View File

@ -21,3 +21,156 @@
*/
#include "MultiPlot.h"
#include "CSV/Player.h"
#include "UI/Dashboard.h"
#include "Misc/ThemeManager.h"
using namespace Widgets;
/**
* Constructor function, configures widget style & signal/slot connections.
*/
MultiPlot::MultiPlot(const int index)
: m_index(index)
{
// Get pointers to serial studio modules
auto dash = UI::Dashboard::getInstance();
auto theme = Misc::ThemeManager::getInstance();
// Invalid index, abort initialization
if (m_index < 0 || m_index >= dash->multiPlotCount())
return;
// Set window palette
QPalette palette;
palette.setColor(QPalette::Base, theme->datasetWindowBackground());
palette.setColor(QPalette::Window, theme->datasetWindowBackground());
setPalette(palette);
// Set plot palette
palette.setColor(QPalette::Base, theme->base());
palette.setColor(QPalette::Highlight, QColor("#f00"));
palette.setColor(QPalette::Text, theme->widgetIndicator1());
palette.setColor(QPalette::Dark, theme->widgetIndicator1());
palette.setColor(QPalette::Light, theme->widgetIndicator1());
palette.setColor(QPalette::ButtonText, theme->widgetIndicator1());
palette.setColor(QPalette::WindowText, theme->widgetIndicator1());
m_plot.setPalette(palette);
m_plot.setCanvasBackground(theme->base());
m_plot.setFrameStyle(QFrame::Plain);
// Configure layout
m_layout.addWidget(&m_plot);
m_layout.setContentsMargins(24, 24, 24, 24);
setLayout(&m_layout);
// Create curves from datasets
auto group = dash->getMultiplot(m_index);
QVector<QString> colors = theme->widgetColors();
for (int i = 0; i < group->datasetCount(); ++i)
{
// Get title
QString title = tr("Unknown");
if (group->getDataset(i))
title = group->getDataset(i)->title();
// Create curve
auto curve = new QwtPlotCurve(title);
// Get curve color
QString color;
if (colors.count() > i)
color = colors.at(i);
else if (i > 0)
color = colors.at(colors.count() % i);
// Configure curve
curve->setPen(QColor(color), 2, Qt::SolidLine);
curve->attach(&m_plot);
// Register curve
m_curves.append(curve);
}
// Add plot legend to display curve names
m_legend.setFrameStyle(QFrame::Plain);
m_plot.insertLegend(&m_legend, QwtPlot::BottomLegend);
// Show plot
updateRange();
m_plot.replot();
m_plot.show();
// React to dashboard events
connect(dash, SIGNAL(updated()), this, SLOT(updateData()));
connect(dash, SIGNAL(pointsChanged()), this, SLOT(updateRange()));
}
/**
* Checks if the widget is enabled, if so, the widget shall be updated
* to display the latest data frame.
*
* If the widget is disabled (e.g. the user hides it, or the external
* window is hidden), then the new data shall be saved to the plot
* vector, but the widget shall not be redrawn.
*/
void MultiPlot::updateData()
{
// Get group
auto group = UI::Dashboard::getInstance()->getMultiplot(m_index);
if (!group)
return;
// Plot each dataset
for (int i = 0; i < group->datasetCount(); ++i)
{
// Get dataset
auto dataset = group->getDataset(i);
if (!dataset)
continue;
// Add point to plot data
memmove(m_yData[i].data(), m_yData[i].data() + 1,
m_yData[i].count() * sizeof(double));
m_yData[i][m_yData[i].count() - 1] = dataset->value().toDouble();
// Widget not enabled, do not redraw
if (!isEnabled())
continue;
// Plot new data
m_curves.at(i)->setSamples(m_xData, m_yData[i]);
}
// Plot widget again
if (isEnabled())
m_plot.replot();
}
/**
* Updates the number of horizontal divisions of the plot
*/
void MultiPlot::updateRange()
{
// Get pointer to dashboard manager
auto dash = UI::Dashboard::getInstance();
// Set number of points
m_xData.clear();
m_yData.clear();
m_xData.reserve(dash->points());
auto group = UI::Dashboard::getInstance()->getMultiplot(m_index);
for (int i = 0; i < dash->points(); ++i)
{
m_xData.append(i);
m_yData.append(QVector<double>());
m_yData[i].reserve(dash->points());
for (int j = 0; j < dash->points(); ++j)
m_yData[i].append(0);
}
// Create curve from data
for (int i = 0; i < group->datasetCount(); ++i)
if (m_curves.count() > i)
m_curves.at(i)->setSamples(m_xData, m_yData[i]);
}

View File

@ -23,4 +23,35 @@
#ifndef WIDGETS_MULTIPLOT_H
#define WIDGETS_MULTIPLOT_H
#include <QwtPlot>
#include <QWidget>
#include <QwtLegend>
#include <QComboBox>
#include <QVBoxLayout>
#include <QwtPlotCurve>
namespace Widgets
{
class MultiPlot : public QWidget
{
Q_OBJECT
public:
MultiPlot(const int index = -1);
private slots:
void updateData();
void updateRange();
private:
int m_index;
QwtPlot m_plot;
QwtLegend m_legend;
QVBoxLayout m_layout;
QVector<double> m_xData;
QVector<QwtPlotCurve *> m_curves;
QVector<QVector<double>> m_yData;
};
}
#endif

View File

@ -21,14 +21,17 @@
*/
#include "Plot.h"
#include "CSV/Player.h"
#include "UI/Dashboard.h"
#include "Misc/ThemeManager.h"
using namespace Widgets;
/**
* Constructor function, configures widget style & signal/slot connections.
*/
Plot::Plot(const int index)
: m_index(index)
, m_count(0)
{
// Get pointers to serial studio modules
auto dash = UI::Dashboard::getInstance();
@ -69,7 +72,7 @@ Plot::Plot(const int index)
// Get curve color
QString color;
auto colors = theme->widgetColors();
QVector<QString> colors = theme->widgetColors();
if (colors.count() > m_index)
color = colors.at(m_index);
else
@ -80,7 +83,7 @@ Plot::Plot(const int index)
// Lazy widgets, get initial properties from dataset
#ifdef LAZY_WIDGETS
auto dataset = UI::Dashboard::getInstance()->getBar(m_index);
auto dataset = UI::Dashboard::getInstance()->getPlot(m_index);
if (dataset)
{
// Set max/min values
@ -102,6 +105,14 @@ Plot::Plot(const int index)
connect(dash, SIGNAL(pointsChanged()), this, SLOT(updateRange()));
}
/**
* Checks if the widget is enabled, if so, the widget shall be updated
* to display the latest data frame.
*
* If the widget is disabled (e.g. the user hides it, or the external
* window is hidden), then the new data shall be saved to the plot
* vector, but the widget shall not be redrawn.
*/
void Plot::updateData()
{
auto dataset = UI::Dashboard::getInstance()->getPlot(m_index);
@ -115,7 +126,7 @@ void Plot::updateData()
if (!isEnabled())
return;
// Update plot properties
// Update plot properties
#ifndef LAZY_WIDGETS
// Set max/min values
auto min = dataset->min();
@ -136,6 +147,9 @@ void Plot::updateData()
}
}
/**
* Updates the number of horizontal divisions of the plot
*/
void Plot::updateRange()
{
// Get pointer to dashboard manager

View File

@ -44,7 +44,6 @@ private slots:
private:
int m_index;
int m_count;
QwtPlot m_plot;
QwtPlotCurve m_curve;
QVBoxLayout m_layout;

View File

@ -28,6 +28,7 @@
#include "Compass.h"
#include "DataGroup.h"
#include "Gyroscope.h"
#include "MultiPlot.h"
#include "Accelerometer.h"
#include <QPushButton>
@ -237,7 +238,7 @@ void WidgetLoader::setWidgetIndex(const int index)
m_widget = new DataGroup(relativeIndex());
break;
case UI::Dashboard::WidgetType::MultiPlot:
m_widget = new QPushButton("Multi-Plot");
m_widget = new MultiPlot(relativeIndex());
break;
case UI::Dashboard::WidgetType::Plot:
m_widget = new Plot(relativeIndex());