diff --git a/assets/qml/Windows/MainWindow.qml b/assets/qml/Windows/MainWindow.qml index f5c953f1..4152f0c9 100644 --- a/assets/qml/Windows/MainWindow.qml +++ b/assets/qml/Windows/MainWindow.qml @@ -38,7 +38,10 @@ ApplicationWindow { // // Quit application on close // - onClosing: Cpp_ModuleManager.quit() + onClosing: { + if (Cpp_JSON_Editor.askSave()) + Cpp_ModuleManager.quit() + } // // Global properties diff --git a/src/JSON/Editor.cpp b/src/JSON/Editor.cpp index daf1bb38..bfcde761 100644 --- a/src/JSON/Editor.cpp +++ b/src/JSON/Editor.cpp @@ -840,12 +840,23 @@ bool Editor::setGroupWidget(const int group, const int widgetId) { // Set widget title grp->m_widget = "accelerometer"; + grp->m_title = tr("Accelerometer"); // Create datasets auto x = new Dataset; auto y = 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 x->m_widget = "x"; y->m_widget = "y"; @@ -865,12 +876,23 @@ bool Editor::setGroupWidget(const int group, const int widgetId) { // Set widget title grp->m_widget = "gyro"; + grp->m_title = tr("Gyroscope"); // Create datasets auto x = new Dataset; auto y = 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 x->m_widget = "x"; y->m_widget = "y"; @@ -890,11 +912,20 @@ bool Editor::setGroupWidget(const int group, const int widgetId) { // Set widget title grp->m_widget = "map"; + grp->m_title = tr("GPS Map"); // Create datasets auto lat = 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 lat->m_widget = "lat"; lon->m_widget = "lon"; @@ -950,27 +981,9 @@ void Editor::addDataset(const int group) auto grp = getGroup(group); 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); - 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")); - - // Update UI emit groupChanged(group); } } @@ -1217,3 +1230,29 @@ void Editor::onDatasetChanged(const int group, const int dataset) (void)dataset; 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; +} diff --git a/src/JSON/Editor.h b/src/JSON/Editor.h index 5e309045..1e7034cb 100644 --- a/src/JSON/Editor.h +++ b/src/JSON/Editor.h @@ -157,6 +157,8 @@ private: Editor(); ~Editor(); + int nextDatasetIndex(); + private: QString m_title; QString m_separator; diff --git a/src/Widgets/Accelerometer.cpp b/src/Widgets/Accelerometer.cpp index ae6909da..177f19b7 100644 --- a/src/Widgets/Accelerometer.cpp +++ b/src/Widgets/Accelerometer.cpp @@ -19,3 +19,137 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + +#include "UI/Dashboard.h" +#include "Accelerometer.h" +#include "Misc/ThemeManager.h" + +#include +#include + +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(); +} diff --git a/src/Widgets/Accelerometer.h b/src/Widgets/Accelerometer.h index 612c407d..cd138af0 100644 --- a/src/Widgets/Accelerometer.h +++ b/src/Widgets/Accelerometer.h @@ -23,6 +23,33 @@ #ifndef WIDGETS_ACCELEROMETER_H #define WIDGETS_ACCELEROMETER_H -#include +#include +#include +#include + +#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 diff --git a/src/Widgets/AnalogGauge.cpp b/src/Widgets/AnalogGauge.cpp index f93b8f34..cdfa3afb 100644 --- a/src/Widgets/AnalogGauge.cpp +++ b/src/Widgets/AnalogGauge.cpp @@ -34,6 +34,8 @@ using namespace Widgets; */ AnalogGauge::AnalogGauge(QWidget *parent) : QwtDial(parent) + , m_label("") + , m_labelEnabled(true) { // Disable controling the gauge with the mouse or keyboard setReadOnly(true); @@ -63,18 +65,33 @@ void AnalogGauge::setLabel(const QString &label) 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. */ void AnalogGauge::drawScaleContents(QPainter *painter, const QPointF ¢er, double radius) const { + // Label disabled, abort + if (!m_labelEnabled) + return; + // Get label font auto labelFont = font(); - labelFont.setPixelSize(1.4 * font().pixelSize()); + labelFont.setPixelSize(1.2 * font().pixelSize()); // 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); // Set text alignment flags diff --git a/src/Widgets/AnalogGauge.h b/src/Widgets/AnalogGauge.h index 0ef318f3..796c5e96 100644 --- a/src/Widgets/AnalogGauge.h +++ b/src/Widgets/AnalogGauge.h @@ -35,6 +35,7 @@ public: QString label() const; void setLabel(const QString &label); + void setLabelEnabled(const bool enabled); protected: virtual void drawScaleContents(QPainter *painter, const QPointF ¢er, @@ -42,6 +43,7 @@ protected: private: QString m_label; + bool m_labelEnabled; }; } diff --git a/src/Widgets/Bar.cpp b/src/Widgets/Bar.cpp index b3ba6fca..ce89c190 100644 --- a/src/Widgets/Bar.cpp +++ b/src/Widgets/Bar.cpp @@ -149,8 +149,10 @@ void Bar::resizeEvent(QResizeEvent *event) auto width = event->size().width(); m_thermo.setPipeWidth(width / 4); QFont font = m_label.font(); - font.setPixelSize(width / 16); + font.setPixelSize(width / 18); 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); event->accept(); } diff --git a/src/Widgets/Bar.h b/src/Widgets/Bar.h index 27bd84ae..54d22900 100644 --- a/src/Widgets/Bar.h +++ b/src/Widgets/Bar.h @@ -39,7 +39,7 @@ public: private slots: void update(); -private: +protected: void resizeEvent(QResizeEvent *event); private: diff --git a/src/Widgets/Compass.cpp b/src/Widgets/Compass.cpp index 59b49a57..c49cc630 100644 --- a/src/Widgets/Compass.cpp +++ b/src/Widgets/Compass.cpp @@ -140,7 +140,8 @@ void Compass::resizeEvent(QResizeEvent *event) compassFont.setPixelSize(event->size().width() / 24); m_label.setFont(labelFont); 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); event->accept(); } diff --git a/src/Widgets/Compass.h b/src/Widgets/Compass.h index 74e76853..97d8cb94 100644 --- a/src/Widgets/Compass.h +++ b/src/Widgets/Compass.h @@ -40,7 +40,7 @@ public: private slots: void update(); -private: +protected: void resizeEvent(QResizeEvent *event); private: diff --git a/src/Widgets/DataGroup.h b/src/Widgets/DataGroup.h index 483298cb..b5212e92 100644 --- a/src/Widgets/DataGroup.h +++ b/src/Widgets/DataGroup.h @@ -42,7 +42,7 @@ public: private slots: void update(); -private: +protected: void resizeEvent(QResizeEvent *event); private: diff --git a/src/Widgets/Gauge.cpp b/src/Widgets/Gauge.cpp index c8ff633b..b6f9d821 100644 --- a/src/Widgets/Gauge.cpp +++ b/src/Widgets/Gauge.cpp @@ -55,17 +55,14 @@ Gauge::Gauge(const int index) auto needle = new QwtDialSimpleNeedle(QwtDialSimpleNeedle::Arrow, true, QColor(needleColor), knobColor); m_gauge.setNeedle(needle); + m_gauge.setLabelEnabled(false); m_gauge.setFont(dash->monoFont()); - // Set gauge scale & label + // Set gauge scale #ifdef LAZY_WIDGETS auto dataset = dash->getGauge(m_index); if (dataset) - { m_gauge.setScale(dataset->min(), dataset->max()); - if (!dataset->units().isEmpty()) - m_gauge.setLabel(dataset->units()); - } #endif // Set gauge palette @@ -80,11 +77,30 @@ Gauge::Gauge(const int index) windowPalette.setColor(QPalette::Window, theme->datasetWindowBackground()); 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.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); + // 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())); } @@ -108,10 +124,11 @@ void Gauge::update() { #ifndef LAZY_WIDGETS m_gauge.setScale(dataset->min(), dataset->max()); - if (!dataset->units().isEmpty()) - m_gauge.setLabel(dataset->units()); #endif + auto value = 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) { - auto font = UI::Dashboard::getInstance()->monoFont(); - font.setPixelSize(event->size().width() / 32); - m_gauge.setFont(font); + 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(); } diff --git a/src/Widgets/Gauge.h b/src/Widgets/Gauge.h index cf938336..c0a5efba 100644 --- a/src/Widgets/Gauge.h +++ b/src/Widgets/Gauge.h @@ -23,8 +23,9 @@ #ifndef WIDGETS_GAUGE_H #define WIDGETS_GAUGE_H +#include #include -#include +#include #include "AnalogGauge.h" @@ -40,13 +41,14 @@ public: private slots: void update(); -private: +protected: void resizeEvent(QResizeEvent *event); private: int m_index; + QLabel m_label; AnalogGauge m_gauge; - QVBoxLayout m_layout; + QHBoxLayout m_layout; }; } diff --git a/src/Widgets/WidgetLoader.cpp b/src/Widgets/WidgetLoader.cpp index 1b42fbde..787bde19 100644 --- a/src/Widgets/WidgetLoader.cpp +++ b/src/Widgets/WidgetLoader.cpp @@ -29,6 +29,7 @@ #include "DataGroup.h" #include "Gyroscope.h" #include "Thermometer.h" +#include "Accelerometer.h" #include #include @@ -263,7 +264,8 @@ void WidgetLoader::setWidgetIndex(const int index) m_widget = new QPushButton("Gyroscope"); break; case UI::Dashboard::WidgetType::Accelerometer: - m_widget = new QPushButton("Accelerometer"); + m_widget = new Accelerometer(relativeIndex()); + m_window.setCentralWidget(new Accelerometer(relativeIndex())); break; case UI::Dashboard::WidgetType::Map: m_widget = new QPushButton("Map");