Implement accelerometer widget

This commit is contained in:
Alex Spataru 2021-09-27 02:12:24 -05:00
parent a4737c81f9
commit 6f22e48b75
15 changed files with 298 additions and 44 deletions

View File

@ -38,7 +38,10 @@ ApplicationWindow {
// //
// Quit application on close // Quit application on close
// //
onClosing: Cpp_ModuleManager.quit() onClosing: {
if (Cpp_JSON_Editor.askSave())
Cpp_ModuleManager.quit()
}
// //
// Global properties // Global properties

View File

@ -840,12 +840,23 @@ bool Editor::setGroupWidget(const int group, const int widgetId)
{ {
// Set widget title // Set widget title
grp->m_widget = "accelerometer"; grp->m_widget = "accelerometer";
grp->m_title = tr("Accelerometer");
// Create datasets // Create datasets
auto x = new Dataset; auto x = new Dataset;
auto y = new Dataset; auto y = new Dataset;
auto z = new Dataset; auto z = new Dataset;
// Set dataset indexes
x->m_index = nextDatasetIndex();
y->m_index = nextDatasetIndex() + 1;
z->m_index = nextDatasetIndex() + 2;
// Set measurement units
x->m_units = "m/s²";
y->m_units = "m/s²";
z->m_units = "m/s²";
// Set dataset properties // Set dataset properties
x->m_widget = "x"; x->m_widget = "x";
y->m_widget = "y"; y->m_widget = "y";
@ -865,12 +876,23 @@ bool Editor::setGroupWidget(const int group, const int widgetId)
{ {
// Set widget title // Set widget title
grp->m_widget = "gyro"; grp->m_widget = "gyro";
grp->m_title = tr("Gyroscope");
// Create datasets // Create datasets
auto x = new Dataset; auto x = new Dataset;
auto y = new Dataset; auto y = new Dataset;
auto z = new Dataset; auto z = new Dataset;
// Set dataset indexes
x->m_index = nextDatasetIndex();
y->m_index = nextDatasetIndex() + 1;
z->m_index = nextDatasetIndex() + 2;
// Set measurement units
x->m_units = "°";
y->m_units = "°";
z->m_units = "°";
// Set dataset properties // Set dataset properties
x->m_widget = "x"; x->m_widget = "x";
y->m_widget = "y"; y->m_widget = "y";
@ -890,11 +912,20 @@ bool Editor::setGroupWidget(const int group, const int widgetId)
{ {
// Set widget title // Set widget title
grp->m_widget = "map"; grp->m_widget = "map";
grp->m_title = tr("GPS Map");
// Create datasets // Create datasets
auto lat = new Dataset; auto lat = new Dataset;
auto lon = new Dataset; auto lon = new Dataset;
// Set dataset indexes
lat->m_index = nextDatasetIndex();
lon->m_index = nextDatasetIndex() + 1;
// Set measurement units
lat->m_units = "°";
lon->m_units = "°";
// Set dataset properties // Set dataset properties
lat->m_widget = "lat"; lat->m_widget = "lat";
lon->m_widget = "lon"; lon->m_widget = "lon";
@ -950,27 +981,9 @@ void Editor::addDataset(const int group)
auto grp = getGroup(group); auto grp = getGroup(group);
if (grp) if (grp)
{ {
// Calculate frame index for dataset
int maxIndex = 1;
for (int i = 0; i < groupCount(); ++i)
{
for (int j = 0; j < datasetCount(i); ++j)
{
auto dataset = getDataset(i, j);
if (dataset)
{
if (dataset->m_index >= maxIndex)
maxIndex = dataset->m_index + 1;
}
}
}
// Add dataset
grp->m_datasets.append(new Dataset); grp->m_datasets.append(new Dataset);
setDatasetIndex(group, grp->m_datasets.count() - 1, maxIndex); setDatasetIndex(group, grp->m_datasets.count() - 1, nextDatasetIndex());
setDatasetTitle(group, grp->m_datasets.count() - 1, tr("New dataset")); setDatasetTitle(group, grp->m_datasets.count() - 1, tr("New dataset"));
// Update UI
emit groupChanged(group); emit groupChanged(group);
} }
} }
@ -1217,3 +1230,29 @@ void Editor::onDatasetChanged(const int group, const int dataset)
(void)dataset; (void)dataset;
setModified(true); setModified(true);
} }
/**
* Gets the number of datasets registered in the projects and
* adds 1 to the result.
*
* This function is used when registering new datasets, so that
* the user does not need to manually specify dataset indexes.
*/
int Editor::nextDatasetIndex()
{
int maxIndex = 1;
for (int i = 0; i < groupCount(); ++i)
{
for (int j = 0; j < datasetCount(i); ++j)
{
auto dataset = getDataset(i, j);
if (dataset)
{
if (dataset->m_index >= maxIndex)
maxIndex = dataset->m_index + 1;
}
}
}
return maxIndex;
}

View File

@ -157,6 +157,8 @@ private:
Editor(); Editor();
~Editor(); ~Editor();
int nextDatasetIndex();
private: private:
QString m_title; QString m_title;
QString m_separator; QString m_separator;

View File

@ -19,3 +19,137 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "UI/Dashboard.h"
#include "Accelerometer.h"
#include "Misc/ThemeManager.h"
#include <QtMath>
#include <QResizeEvent>
using namespace Widgets;
Accelerometer::Accelerometer(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->accelerometerCount())
return;
// Get needle & knob color
QString needleColor;
auto colors = theme->widgetColors();
auto knobColor = theme->widgetControlBackground();
if (colors.count() > m_index)
needleColor = colors.at(m_index);
else
needleColor = colors.at(colors.count() % m_index);
// Configure gauge needle
auto needle = new QwtDialSimpleNeedle(QwtDialSimpleNeedle::Arrow, true,
QColor(needleColor), knobColor);
m_gauge.setNeedle(needle);
m_gauge.setFont(dash->monoFont());
// Set gauge scale & display angles
m_gauge.setScale(0, 12);
m_gauge.setScaleArc(90, 360);
m_gauge.setLabelEnabled(false);
// Set gauge palette
QPalette gaugePalette;
gaugePalette.setColor(QPalette::WindowText, theme->base());
gaugePalette.setColor(QPalette::Text, theme->widgetIndicator1());
m_gauge.setPalette(gaugePalette);
// Set window palette
QPalette windowPalette;
windowPalette.setColor(QPalette::Base, theme->datasetWindowBackground());
windowPalette.setColor(QPalette::Window, theme->datasetWindowBackground());
setPalette(windowPalette);
// Configure label style
QFont font = dash->monoFont();
font.setPixelSize(24);
m_label.setFont(font);
m_label.setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
// Configure layout
m_layout.addWidget(&m_gauge);
m_layout.addWidget(&m_label);
m_layout.setSpacing(24);
m_layout.setStretch(0, 0);
m_layout.setStretch(1, 1);
m_layout.setContentsMargins(24, 24, 24, 24);
setLayout(&m_layout);
// Set stylesheets
// clang-format off
auto valueQSS = QSS("background-color:%1; color:%2; border:1px solid %3;",
theme->base(),
theme->widgetForegroundPrimary(),
theme->widgetIndicator1());
m_label.setStyleSheet(valueQSS);
// clang-format on
// React to dashboard events
connect(dash, SIGNAL(updated()), this, SLOT(update()));
}
void Accelerometer::update()
{
// Widget not enabled, do nothing
if (!isEnabled())
return;
// Update accelerometer values
auto accelerometer = UI::Dashboard::getInstance()->getAccelerometer(m_index);
if (accelerometer)
{
if (accelerometer->datasetCount() != 3)
return;
double x = 0;
double y = 0;
double z = 0;
JSON::Dataset *dataset;
for (int i = 0; i < 3; ++i)
{
dataset = accelerometer->getDataset(i);
if (dataset->widget() == "x")
x = dataset->value().toDouble();
if (dataset->widget() == "y")
y = dataset->value().toDouble();
if (dataset->widget() == "z")
z = dataset->value().toDouble();
}
x /= 9.18;
y /= 9.18;
z /= 9.18;
const double G = qSqrt(qPow(x, 2) + qPow(y, 2) + qPow(z, 2));
m_gauge.setValue(G);
m_label.setText(QString("%1 G").arg(QString::number(G, 'f', 2)));
}
}
void Accelerometer::resizeEvent(QResizeEvent *event)
{
auto labelFont = UI::Dashboard::getInstance()->monoFont();
auto gaugeFont = UI::Dashboard::getInstance()->monoFont();
labelFont.setPixelSize(event->size().width() / 18);
gaugeFont.setPixelSize(event->size().width() / 24);
m_label.setFont(labelFont);
m_gauge.setFont(gaugeFont);
m_label.setMinimumWidth(event->size().width() * 0.4);
m_label.setMaximumWidth(event->size().width() * 0.4);
m_label.setMaximumHeight(event->size().height() * 0.4);
event->accept();
}

View File

@ -23,6 +23,33 @@
#ifndef WIDGETS_ACCELEROMETER_H #ifndef WIDGETS_ACCELEROMETER_H
#define WIDGETS_ACCELEROMETER_H #define WIDGETS_ACCELEROMETER_H
#include #include <QLabel>
#include <QWidget>
#include <QHBoxLayout>
#include "AnalogGauge.h"
namespace Widgets
{
class Accelerometer : public QWidget
{
Q_OBJECT
public:
Accelerometer(const int index = -1);
private slots:
void update();
protected:
void resizeEvent(QResizeEvent *event);
private:
int m_index;
QLabel m_label;
AnalogGauge m_gauge;
QHBoxLayout m_layout;
};
}
#endif #endif

View File

@ -34,6 +34,8 @@ using namespace Widgets;
*/ */
AnalogGauge::AnalogGauge(QWidget *parent) AnalogGauge::AnalogGauge(QWidget *parent)
: QwtDial(parent) : QwtDial(parent)
, m_label("")
, m_labelEnabled(true)
{ {
// Disable controling the gauge with the mouse or keyboard // Disable controling the gauge with the mouse or keyboard
setReadOnly(true); setReadOnly(true);
@ -63,18 +65,33 @@ void AnalogGauge::setLabel(const QString &label)
update(); update();
} }
/**
* Enables or disables the label that displays the current
* value. For example, the normal gauge widget enables the
* label, while the accelerometer does not.
*/
void AnalogGauge::setLabelEnabled(const bool enabled)
{
m_labelEnabled = enabled;
update();
}
/** /**
* Re-draws the label that displays the current value & units. * Re-draws the label that displays the current value & units.
*/ */
void AnalogGauge::drawScaleContents(QPainter *painter, const QPointF &center, void AnalogGauge::drawScaleContents(QPainter *painter, const QPointF &center,
double radius) const double radius) const
{ {
// Label disabled, abort
if (!m_labelEnabled)
return;
// Get label font // Get label font
auto labelFont = font(); auto labelFont = font();
labelFont.setPixelSize(1.4 * font().pixelSize()); labelFont.setPixelSize(1.2 * font().pixelSize());
// Create draw rectangle // Create draw rectangle
QRectF rect(0.0, 0.0, 2.0 * radius, 2.0 * radius - labelFont.pixelSize() * 2); QRectF rect(0.0, 0.0, 2.0 * radius, 2.0 * radius - labelFont.pixelSize() * 6);
rect.moveCenter(center); rect.moveCenter(center);
// Set text alignment flags // Set text alignment flags

View File

@ -35,6 +35,7 @@ public:
QString label() const; QString label() const;
void setLabel(const QString &label); void setLabel(const QString &label);
void setLabelEnabled(const bool enabled);
protected: protected:
virtual void drawScaleContents(QPainter *painter, const QPointF &center, virtual void drawScaleContents(QPainter *painter, const QPointF &center,
@ -42,6 +43,7 @@ protected:
private: private:
QString m_label; QString m_label;
bool m_labelEnabled;
}; };
} }

View File

@ -149,8 +149,10 @@ void Bar::resizeEvent(QResizeEvent *event)
auto width = event->size().width(); auto width = event->size().width();
m_thermo.setPipeWidth(width / 4); m_thermo.setPipeWidth(width / 4);
QFont font = m_label.font(); QFont font = m_label.font();
font.setPixelSize(width / 16); font.setPixelSize(width / 18);
m_label.setFont(font); m_label.setFont(font);
m_label.setMinimumWidth(event->size().width() * 0.4);
m_label.setMaximumWidth(event->size().width() * 0.4);
m_label.setMaximumHeight(event->size().height() * 0.4); m_label.setMaximumHeight(event->size().height() * 0.4);
event->accept(); event->accept();
} }

View File

@ -39,7 +39,7 @@ public:
private slots: private slots:
void update(); void update();
private: protected:
void resizeEvent(QResizeEvent *event); void resizeEvent(QResizeEvent *event);
private: private:

View File

@ -140,7 +140,8 @@ void Compass::resizeEvent(QResizeEvent *event)
compassFont.setPixelSize(event->size().width() / 24); compassFont.setPixelSize(event->size().width() / 24);
m_label.setFont(labelFont); m_label.setFont(labelFont);
m_compass.setFont(compassFont); m_compass.setFont(compassFont);
m_label.setMaximumWidth(event->size().width() * 0.3); m_label.setMinimumWidth(event->size().width() * 0.4);
m_label.setMaximumWidth(event->size().width() * 0.4);
m_label.setMaximumHeight(event->size().height() * 0.4); m_label.setMaximumHeight(event->size().height() * 0.4);
event->accept(); event->accept();
} }

View File

@ -40,7 +40,7 @@ public:
private slots: private slots:
void update(); void update();
private: protected:
void resizeEvent(QResizeEvent *event); void resizeEvent(QResizeEvent *event);
private: private:

View File

@ -42,7 +42,7 @@ public:
private slots: private slots:
void update(); void update();
private: protected:
void resizeEvent(QResizeEvent *event); void resizeEvent(QResizeEvent *event);
private: private:

View File

@ -55,17 +55,14 @@ Gauge::Gauge(const int index)
auto needle = new QwtDialSimpleNeedle(QwtDialSimpleNeedle::Arrow, true, auto needle = new QwtDialSimpleNeedle(QwtDialSimpleNeedle::Arrow, true,
QColor(needleColor), knobColor); QColor(needleColor), knobColor);
m_gauge.setNeedle(needle); m_gauge.setNeedle(needle);
m_gauge.setLabelEnabled(false);
m_gauge.setFont(dash->monoFont()); m_gauge.setFont(dash->monoFont());
// Set gauge scale & label // Set gauge scale
#ifdef LAZY_WIDGETS #ifdef LAZY_WIDGETS
auto dataset = dash->getGauge(m_index); auto dataset = dash->getGauge(m_index);
if (dataset) if (dataset)
{
m_gauge.setScale(dataset->min(), dataset->max()); m_gauge.setScale(dataset->min(), dataset->max());
if (!dataset->units().isEmpty())
m_gauge.setLabel(dataset->units());
}
#endif #endif
// Set gauge palette // Set gauge palette
@ -80,11 +77,30 @@ Gauge::Gauge(const int index)
windowPalette.setColor(QPalette::Window, theme->datasetWindowBackground()); windowPalette.setColor(QPalette::Window, theme->datasetWindowBackground());
setPalette(windowPalette); setPalette(windowPalette);
// Add gauge to layout // Configure label style
QFont font = dash->monoFont();
font.setPixelSize(24);
m_label.setFont(font);
m_label.setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
// Configure layout
m_layout.addWidget(&m_gauge); m_layout.addWidget(&m_gauge);
m_layout.setContentsMargins(8, 8, 8, 8); m_layout.addWidget(&m_label);
m_layout.setSpacing(24);
m_layout.setStretch(0, 0);
m_layout.setStretch(1, 1);
m_layout.setContentsMargins(24, 24, 24, 24);
setLayout(&m_layout); setLayout(&m_layout);
// Set stylesheets
// clang-format off
auto valueQSS = QSS("background-color:%1; color:%2; border:1px solid %3;",
theme->base(),
theme->widgetForegroundPrimary(),
theme->widgetIndicator1());
m_label.setStyleSheet(valueQSS);
// clang-format on
// React to dashboard events // React to dashboard events
connect(dash, SIGNAL(updated()), this, SLOT(update())); connect(dash, SIGNAL(updated()), this, SLOT(update()));
} }
@ -108,10 +124,11 @@ void Gauge::update()
{ {
#ifndef LAZY_WIDGETS #ifndef LAZY_WIDGETS
m_gauge.setScale(dataset->min(), dataset->max()); m_gauge.setScale(dataset->min(), dataset->max());
if (!dataset->units().isEmpty())
m_gauge.setLabel(dataset->units());
#endif #endif
auto value = dataset->value().toDouble();
m_gauge.setValue(dataset->value().toDouble()); m_gauge.setValue(dataset->value().toDouble());
m_label.setText(
QString("%1 %2").arg(QString::number(value, 'f', 2), dataset->units()));
} }
} }
@ -120,8 +137,14 @@ void Gauge::update()
*/ */
void Gauge::resizeEvent(QResizeEvent *event) void Gauge::resizeEvent(QResizeEvent *event)
{ {
auto font = UI::Dashboard::getInstance()->monoFont(); auto labelFont = UI::Dashboard::getInstance()->monoFont();
font.setPixelSize(event->size().width() / 32); auto gaugeFont = UI::Dashboard::getInstance()->monoFont();
m_gauge.setFont(font); labelFont.setPixelSize(event->size().width() / 18);
gaugeFont.setPixelSize(event->size().width() / 24);
m_label.setFont(labelFont);
m_gauge.setFont(gaugeFont);
m_label.setMinimumWidth(event->size().width() * 0.4);
m_label.setMaximumWidth(event->size().width() * 0.4);
m_label.setMaximumHeight(event->size().height() * 0.4);
event->accept(); event->accept();
} }

View File

@ -23,8 +23,9 @@
#ifndef WIDGETS_GAUGE_H #ifndef WIDGETS_GAUGE_H
#define WIDGETS_GAUGE_H #define WIDGETS_GAUGE_H
#include <QLabel>
#include <QWidget> #include <QWidget>
#include <QVBoxLayout> #include <QHBoxLayout>
#include "AnalogGauge.h" #include "AnalogGauge.h"
@ -40,13 +41,14 @@ public:
private slots: private slots:
void update(); void update();
private: protected:
void resizeEvent(QResizeEvent *event); void resizeEvent(QResizeEvent *event);
private: private:
int m_index; int m_index;
QLabel m_label;
AnalogGauge m_gauge; AnalogGauge m_gauge;
QVBoxLayout m_layout; QHBoxLayout m_layout;
}; };
} }

View File

@ -29,6 +29,7 @@
#include "DataGroup.h" #include "DataGroup.h"
#include "Gyroscope.h" #include "Gyroscope.h"
#include "Thermometer.h" #include "Thermometer.h"
#include "Accelerometer.h"
#include <QPushButton> #include <QPushButton>
#include <QApplication> #include <QApplication>
@ -263,7 +264,8 @@ void WidgetLoader::setWidgetIndex(const int index)
m_widget = new QPushButton("Gyroscope"); m_widget = new QPushButton("Gyroscope");
break; break;
case UI::Dashboard::WidgetType::Accelerometer: case UI::Dashboard::WidgetType::Accelerometer:
m_widget = new QPushButton("Accelerometer"); m_widget = new Accelerometer(relativeIndex());
m_window.setCentralWidget(new Accelerometer(relativeIndex()));
break; break;
case UI::Dashboard::WidgetType::Map: case UI::Dashboard::WidgetType::Map:
m_widget = new QPushButton("Map"); m_widget = new QPushButton("Map");