Begin working on bar widget

This commit is contained in:
Alex Spataru 2021-09-26 05:42:22 -05:00
parent 000c202a10
commit 1bf1d2a714
18 changed files with 266 additions and 23 deletions

View File

@ -55,6 +55,7 @@ Widgets.Window {
// //
ColumnLayout { ColumnLayout {
x: app.spacing x: app.spacing
spacing: app.spacing / 2
width: parent.width - 10 - 2 * app.spacing width: parent.width - 10 - 2 * app.spacing
// //

View File

@ -5,6 +5,7 @@ import QtGraphicalEffects 1.0
ColumnLayout { ColumnLayout {
id: root id: root
visible: count > 0
spacing: app.spacing spacing: app.spacing
property int count: 0 property int count: 0
@ -72,6 +73,7 @@ ColumnLayout {
} }
Item { Item {
height: hideAll.checked ? 0 : app.spacing height: app.spacing
visible: !hideAll.checked && count > 0
} }
} }

View File

@ -174,6 +174,25 @@ Widgets.Window {
} }
} }
//
// Widget maximum value
//
Label {
text: qsTr("Alarm value:")
visible: widget.currentIndex == 1 || widget.currentIndex == 2
} TextField {
id: alarm
Layout.fillWidth: true
text: Cpp_JSON_Editor.datasetWidgetAlarm(group, dataset)
visible: widget.currentIndex == 1 || widget.currentIndex == 2
onTextChanged: Cpp_JSON_Editor.setDatasetWidgetAlarm(group, dataset, text)
validator: DoubleValidator {
top: parseFloat(max.text)
bottom: parseFloat(min.text)
}
}
// //
// Vertical spacer // Vertical spacer
// //

View File

@ -144,7 +144,7 @@ Widgets.Window {
columnSpacing: app.spacing columnSpacing: app.spacing
Layout.fillHeight: repeater.model > 0 Layout.fillHeight: repeater.model > 0
columns: Math.floor(column.width / 320) columns: Math.floor(column.width / 320)
Layout.minimumHeight: (repeater.model / columns) * 300 Layout.minimumHeight: (repeater.model / columns) * 320
Repeater { Repeater {
id: repeater id: repeater
@ -154,7 +154,7 @@ Widgets.Window {
group: root.group group: root.group
Layout.fillWidth: true Layout.fillWidth: true
Layout.minimumWidth: 320 Layout.minimumWidth: 320
Layout.minimumHeight: 300 Layout.minimumHeight: 320
showGroupWidget: widget.currentIndex > 0 showGroupWidget: widget.currentIndex > 0
} }
} }

View File

@ -37,7 +37,7 @@
"graphDialBorder":"#222222", "graphDialBorder":"#222222",
"datasetTextPrimary":"#24476a", "datasetTextPrimary":"#24476a",
"datasetTextSecondary":"#666666", "datasetTextSecondary":"#666666",
"datasetWindowBackground":"#fafafa", "datasetWindowBackground":"#e8e8e8",
"datasetWindowBorder":"#336698", "datasetWindowBorder":"#336698",
"embeddedWindowBackground":"#f1f1f1", "embeddedWindowBackground":"#f1f1f1",
"ledEnabled":"#0072C3", "ledEnabled":"#0072C3",

View File

@ -46,6 +46,30 @@ bool Dataset::graph() const
return m_graph; return m_graph;
} }
/**
* Returns the minimum value of the dataset
*/
double Dataset::min() const
{
return m_min.toDouble();
}
/**
* Returns the maximum value of the dataset
*/
double Dataset::max() const
{
return m_max.toDouble();
}
/**
* Returns the alarm level of the dataset
*/
double Dataset::alarm() const
{
return m_alarm.toDouble();
}
/** /**
* @return The title/description of this dataset * @return The title/description of this dataset
*/ */
@ -103,22 +127,34 @@ bool Dataset::read(const QJsonObject &object)
auto value = object.value("v").toVariant().toString(); auto value = object.value("v").toVariant().toString();
auto units = object.value("u").toVariant().toString(); auto units = object.value("u").toVariant().toString();
auto widget = object.value("w").toVariant().toString(); auto widget = object.value("w").toVariant().toString();
auto min = object.value("min").toVariant().toString();
auto max = object.value("max").toVariant().toString();
auto alarm = object.value("alarm").toVariant().toString();
min = min.replace("\n", "");
min = min.replace("\r", "");
max = max.replace("\n", "");
max = max.replace("\r", "");
title = title.replace("\n", ""); title = title.replace("\n", "");
title = title.replace("\r", ""); title = title.replace("\r", "");
value = value.replace("\n", ""); value = value.replace("\n", "");
value = value.replace("\r", ""); value = value.replace("\r", "");
units = units.replace("\n", ""); units = units.replace("\n", "");
units = units.replace("\r", ""); units = units.replace("\r", "");
alarm = alarm.replace("\n", "");
alarm = alarm.replace("\r", "");
widget = widget.replace("\n", ""); widget = widget.replace("\n", "");
widget = widget.replace("\r", ""); widget = widget.replace("\r", "");
if (!value.isEmpty() && !title.isEmpty()) if (!value.isEmpty() && !title.isEmpty())
{ {
m_min = min;
m_max = max;
m_graph = graph; m_graph = graph;
m_title = title; m_title = title;
m_units = units; m_units = units;
m_value = value; m_value = value;
m_alarm = alarm;
m_widget = widget; m_widget = widget;
m_jsonData = object; m_jsonData = object;

View File

@ -57,6 +57,9 @@ public:
Dataset(QObject *parent = nullptr); Dataset(QObject *parent = nullptr);
bool graph() const; bool graph() const;
double min() const;
double max() const;
double alarm() const;
QString title() const; QString title() const;
QString value() const; QString value() const;
QString units() const; QString units() const;
@ -77,6 +80,7 @@ private:
int m_index; int m_index;
QString m_max; QString m_max;
QString m_min; QString m_min;
QString m_alarm;
friend class Editor; friend class Editor;
}; };
} }

View File

@ -311,6 +311,7 @@ bool Editor::saveJsonFile()
dataset.insert("v", "%" + QString::number(datasetIndex(i, j))); dataset.insert("v", "%" + QString::number(datasetIndex(i, j)));
dataset.insert("min", datasetWidgetMin(i, j).toDouble()); dataset.insert("min", datasetWidgetMin(i, j).toDouble());
dataset.insert("max", datasetWidgetMax(i, j).toDouble()); dataset.insert("max", datasetWidgetMax(i, j).toDouble());
dataset.insert("alarm", datasetWidgetAlarm(i, j).toDouble());
// Add dataset to array // Add dataset to array
datasets.append(dataset); datasets.append(dataset);
@ -548,6 +549,27 @@ QString Editor::datasetWidgetMax(const int group, const int dataset)
return 0; return 0;
} }
/**
* Returns the widget alarm value of the specified dataset.
* This option is used by the bar & gauge widgets.
*
* @param group index of the group in which the dataset belongs
* @param dataset index of the dataset
*/
QString Editor::datasetWidgetAlarm(const int group, const int dataset)
{
auto set = getDataset(group, dataset);
if (set)
{
if (set->m_alarm.isEmpty())
return set->m_max;
else
return set->m_alarm;
}
return 0;
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public slots // Public slots
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -669,8 +691,10 @@ void Editor::openJsonFile(const QString &path)
// Get max/min texts // Get max/min texts
auto min = jsonDataset.value("min").toDouble(); auto min = jsonDataset.value("min").toDouble();
auto max = jsonDataset.value("max").toDouble(); auto max = jsonDataset.value("max").toDouble();
auto alarm = jsonDataset.value("alarm").toDouble();
setDatasetWidgetMin(group, dataset, QString::number(min)); setDatasetWidgetMin(group, dataset, QString::number(min));
setDatasetWidgetMax(group, dataset, QString::number(max)); setDatasetWidgetMax(group, dataset, QString::number(max));
setDatasetWidgetAlarm(group, dataset, QString::number(alarm));
// Calculate dataset index // Calculate dataset index
auto index = jsonDataset.value("v").toString(); auto index = jsonDataset.value("v").toString();
@ -1118,6 +1142,25 @@ void Editor::setDatasetWidgetData(const int group, const int dataset,
} }
} }
/**
* Updates the @a alarm value used by the bar & gauge widgets for the given
* @a dataset. The value is specified in a @c QString to facilitate integration
* with the QML user interface.
*
* @param group index of the group in which the dataset belongs
* @param dataset index of the dataset
*/
void Editor::setDatasetWidgetAlarm(const int group, const int dataset,
const QString &alarm)
{
auto set = getDataset(group, dataset);
if (set)
{
set->m_alarm = alarm;
emit datasetChanged(group, dataset);
}
}
/** /**
* Updates the @a modified flag of the current JSON project. * Updates the @a modified flag of the current JSON project.
* This flag is used to know if we should ask the user to save * This flag is used to know if we should ask the user to save

View File

@ -112,6 +112,7 @@ public:
Q_INVOKABLE int datasetWidgetIndex(const int group, const int dataset); Q_INVOKABLE int datasetWidgetIndex(const int group, const int dataset);
Q_INVOKABLE QString datasetWidgetMin(const int group, const int dataset); Q_INVOKABLE QString datasetWidgetMin(const int group, const int dataset);
Q_INVOKABLE QString datasetWidgetMax(const int group, const int dataset); Q_INVOKABLE QString datasetWidgetMax(const int group, const int dataset);
Q_INVOKABLE QString datasetWidgetAlarm(const int group, const int dataset);
Q_INVOKABLE bool setGroupWidget(const int group, const int widgetId); Q_INVOKABLE bool setGroupWidget(const int group, const int widgetId);
@ -142,6 +143,7 @@ public slots:
void setDatasetWidgetMin(const int group, const int dataset, const QString &minimum); void setDatasetWidgetMin(const int group, const int dataset, const QString &minimum);
void setDatasetWidgetMax(const int group, const int dataset, const QString &maximum); void setDatasetWidgetMax(const int group, const int dataset, const QString &maximum);
void setDatasetWidgetData(const int group, const int dataset, const QString &widget); void setDatasetWidgetData(const int group, const int dataset, const QString &widget);
void setDatasetWidgetAlarm(const int group, const int dataset, const QString &alarm);
private slots: private slots:
void setModified(const bool modified); void setModified(const bool modified);

View File

@ -84,6 +84,14 @@ JSON::Group *Dashboard::getGroup(const int index)
return nullptr; return nullptr;
} }
JSON::Dataset *Dashboard::getBar(const int index)
{
if (index < m_barWidgets.count())
return m_barWidgets.at(index);
return nullptr;
}
JSON::Dataset *Dashboard::getCompass(const int index) JSON::Dataset *Dashboard::getCompass(const int index)
{ {
if (index < m_compassWidgets.count()) if (index < m_compassWidgets.count())

View File

@ -126,6 +126,7 @@ public:
QFont monoFont() const; QFont monoFont() const;
JSON::Group *getGroup(const int index); JSON::Group *getGroup(const int index);
JSON::Dataset *getBar(const int index);
JSON::Dataset *getCompass(const int index); JSON::Dataset *getCompass(const int index);
QString title(); QString title();

View File

@ -21,3 +21,60 @@
*/ */
#include "Bar.h" #include "Bar.h"
#include "UI/Dashboard.h"
#include "Misc/ThemeManager.h"
using namespace Widgets;
Bar::Bar(const int index)
: m_index(index)
{
if (m_index >= 0)
{
// Configure thermo & add it to layout
m_layout.addWidget(&m_thermo);
m_layout.setContentsMargins(24, 24, 24, 24);
setLayout(&m_layout);
// Get thermo color
QString color;
auto theme = Misc::ThemeManager::getInstance();
auto barcl = theme->barWidgetColors();
if (barcl.count() > m_index)
color = barcl.at(m_index);
else
color = barcl.at(barcl.count() % m_index);
// Configure thermo style
m_thermo.setPipeWidth(64);
m_thermo.setFillBrush(QBrush(QColor(color)));
// Set window background
// clang-format off
auto qss = QString("background-color: %1;").arg(theme->datasetWindowBackground().name());
setStyleSheet(qss);
// React to dashboard events
connect(UI::Dashboard::getInstance(),
&UI::Dashboard::updated,
this, &Bar::update);
// clang-format on
}
}
void Bar::update()
{
// Widget not enabled, do nothing
if (!isEnabled())
return;
// Update bar level
auto dataset = UI::Dashboard::getInstance()->getBar(m_index);
if (dataset)
{
m_thermo.setAlarmLevel(dataset->alarm());
m_thermo.setAlarmEnabled(m_thermo.alarmLevel() > 0);
m_thermo.setScale(dataset->min(), dataset->max());
m_thermo.setValue(dataset->value().toDouble());
}
}

View File

@ -23,4 +23,26 @@
#ifndef WIDGETS_BAR_H #ifndef WIDGETS_BAR_H
#define WIDGETS_BAR_H #define WIDGETS_BAR_H
#include <QwtThermo>
#include <QVBoxLayout>
namespace Widgets
{
class Bar : public QWidget
{
Q_OBJECT
public:
Bar(const int index = -1);
private slots:
void update();
private:
int m_index;
QwtThermo m_thermo;
QVBoxLayout m_layout;
};
}
#endif #endif

View File

@ -29,6 +29,9 @@
using namespace Widgets; using namespace Widgets;
/**
* Configures the compass widget style & the signals/slots with the dashboard module
*/
Compass::Compass(const int index) Compass::Compass(const int index)
: m_index(index) : m_index(index)
{ {
@ -36,32 +39,43 @@ Compass::Compass(const int index)
if (m_index < 0) if (m_index < 0)
return; return;
// clang-format off
// Configure compass // Configure compass
m_compass.setScale(0, 360); m_compass.setScale(0, 360);
m_compass.setNeedle( m_compass.setLineWidth(2);
new QwtCompassMagnetNeedle(QwtCompassMagnetNeedle::TriangleStyle)); m_compass.setFrameShadow(QwtDial::Sunken);
m_compass.setNeedle(new QwtCompassMagnetNeedle(QwtCompassMagnetNeedle::TriangleStyle));
// Set stylesheet
auto theme = Misc::ThemeManager::getInstance();
auto qss = QString("background-color: %1;").arg(theme->datasetWindowBackground().name());
setStyleSheet(qss);
// Add compass to layout // Add compass to layout
m_layout.addWidget(&m_compass); m_layout.addWidget(&m_compass);
m_layout.setContentsMargins(24, 24, 24, 24); m_layout.setContentsMargins(24, 24, 24, 24);
setLayout(&m_layout); setLayout(&m_layout);
// Set stylesheet
auto theme = Misc::ThemeManager::getInstance();
auto qss
= QString("background-color: %1;").arg(theme->datasetWindowBackground().name());
setStyleSheet(qss);
// React to dashboard events // React to dashboard events
connect(UI::Dashboard::getInstance(), &UI::Dashboard::updated, this, connect(UI::Dashboard::getInstance(),
&Compass::update); &UI::Dashboard::updated,
this, &Compass::update);
// clang-format on
} }
/**
* Updates the widget's data
*/
void Compass::update() void Compass::update()
{ {
auto dash = UI::Dashboard::getInstance(); // Widget not enabled, do nothing
auto data = dash->getCompass(m_index); if (!isEnabled())
return;
if (data) // Update compass heading
m_compass.setValue(data->value().toDouble()); auto dataset = UI::Dashboard::getInstance()->getCompass(m_index);
if (dataset)
m_compass.setValue(dataset->value().toDouble());
} }

View File

@ -28,17 +28,26 @@
using namespace Widgets; using namespace Widgets;
/**
* Generates the user interface elements & layout
*/
DataGroup::DataGroup(const int index) DataGroup::DataGroup(const int index)
: m_index(index) : m_index(index)
{ {
if (m_index >= 0) if (m_index >= 0)
{ {
// clang-format off
createUserInterface(); createUserInterface();
connect(UI::Dashboard::getInstance(), &UI::Dashboard::updated, this, connect(UI::Dashboard::getInstance(),
&DataGroup::updateUserInterface); &UI::Dashboard::updated,
this, &DataGroup::updateUserInterface);
// clang-format on
} }
} }
/**
* Frees the memory allocated for each label that represents a dataset
*/
DataGroup::~DataGroup() DataGroup::~DataGroup()
{ {
foreach (auto icon, m_icons) foreach (auto icon, m_icons)
@ -55,6 +64,11 @@ DataGroup::~DataGroup()
delete m_mainLayout; delete m_mainLayout;
} }
/**
* Creates a grid layout that contains the labels for each dataset.
* The grid layout is then configured to be contained by a scroll area,
* which is useful in the case that a group has a lot of elements inside it.
*/
void DataGroup::createUserInterface() void DataGroup::createUserInterface()
{ {
// Get group pointer // Get group pointer
@ -155,6 +169,9 @@ void DataGroup::createUserInterface()
m_dataContainer->setStyleSheet(windwQSS); m_dataContainer->setStyleSheet(windwQSS);
} }
/**
* Updates the dataset labels corresponding to the group that this widget is visualizing.
*/
void DataGroup::updateUserInterface() void DataGroup::updateUserInterface()
{ {
// Widget not enabled, do nothing // Widget not enabled, do nothing

View File

@ -19,3 +19,5 @@
* 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 "Gauge.h"

View File

@ -23,4 +23,16 @@
#ifndef WIDGETS_GAUGE_H #ifndef WIDGETS_GAUGE_H
#define WIDGETS_GAUGE_H #define WIDGETS_GAUGE_H
#include <QWidget>
#include <QwtDial>
#include <QwtDialNeedle>
namespace Widgets
{
class Gauge : public QWidget
{
Q_OBJECT
};
}
#endif #endif

View File

@ -57,10 +57,12 @@ WidgetLoader::WidgetLoader(QQuickItem *parent)
m_window.setMinimumHeight(480); m_window.setMinimumHeight(480);
// Configure window style sheet // Configure window style sheet
// clang-format off
auto theme = Misc::ThemeManager::getInstance(); auto theme = Misc::ThemeManager::getInstance();
auto qss auto qss = QString("background-color: %1;").arg(
= QString("background-color: %1;").arg(theme->datasetWindowBackground().name()); theme->datasetWindowBackground().name());
m_window.setStyleSheet(qss); m_window.setStyleSheet(qss);
// clang-format on
// Resize widget to fit QML item size // Resize widget to fit QML item size
connect(this, &QQuickPaintedItem::widthChanged, this, connect(this, &QQuickPaintedItem::widthChanged, this,
@ -244,7 +246,8 @@ void WidgetLoader::setWidgetIndex(const int index)
m_widget = new QPushButton("Plot"); m_widget = new QPushButton("Plot");
break; break;
case UI::Dashboard::WidgetType::Bar: case UI::Dashboard::WidgetType::Bar:
m_widget = new QPushButton("Bar"); m_widget = new Bar(relativeIndex());
m_window.setCentralWidget(new Bar(relativeIndex()));
break; break;
case UI::Dashboard::WidgetType::Gauge: case UI::Dashboard::WidgetType::Gauge:
m_widget = new QPushButton("Gauge"); m_widget = new QPushButton("Gauge");