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 {
x: app.spacing
spacing: app.spacing / 2
width: parent.width - 10 - 2 * app.spacing
//

View File

@ -5,6 +5,7 @@ import QtGraphicalEffects 1.0
ColumnLayout {
id: root
visible: count > 0
spacing: app.spacing
property int count: 0
@ -72,6 +73,7 @@ ColumnLayout {
}
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
//

View File

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

View File

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

View File

@ -46,6 +46,30 @@ bool Dataset::graph() const
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
*/
@ -103,22 +127,34 @@ bool Dataset::read(const QJsonObject &object)
auto value = object.value("v").toVariant().toString();
auto units = object.value("u").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("\r", "");
value = value.replace("\n", "");
value = value.replace("\r", "");
units = units.replace("\n", "");
units = units.replace("\r", "");
alarm = alarm.replace("\n", "");
alarm = alarm.replace("\r", "");
widget = widget.replace("\n", "");
widget = widget.replace("\r", "");
if (!value.isEmpty() && !title.isEmpty())
{
m_min = min;
m_max = max;
m_graph = graph;
m_title = title;
m_units = units;
m_value = value;
m_alarm = alarm;
m_widget = widget;
m_jsonData = object;

View File

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

View File

@ -311,6 +311,7 @@ bool Editor::saveJsonFile()
dataset.insert("v", "%" + QString::number(datasetIndex(i, j)));
dataset.insert("min", datasetWidgetMin(i, j).toDouble());
dataset.insert("max", datasetWidgetMax(i, j).toDouble());
dataset.insert("alarm", datasetWidgetAlarm(i, j).toDouble());
// Add dataset to array
datasets.append(dataset);
@ -548,6 +549,27 @@ QString Editor::datasetWidgetMax(const int group, const int dataset)
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
//--------------------------------------------------------------------------------------------------
@ -669,8 +691,10 @@ void Editor::openJsonFile(const QString &path)
// Get max/min texts
auto min = jsonDataset.value("min").toDouble();
auto max = jsonDataset.value("max").toDouble();
auto alarm = jsonDataset.value("alarm").toDouble();
setDatasetWidgetMin(group, dataset, QString::number(min));
setDatasetWidgetMax(group, dataset, QString::number(max));
setDatasetWidgetAlarm(group, dataset, QString::number(alarm));
// Calculate dataset index
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.
* 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 QString datasetWidgetMin(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);
@ -142,6 +143,7 @@ public slots:
void setDatasetWidgetMin(const int group, const int dataset, const QString &minimum);
void setDatasetWidgetMax(const int group, const int dataset, const QString &maximum);
void setDatasetWidgetData(const int group, const int dataset, const QString &widget);
void setDatasetWidgetAlarm(const int group, const int dataset, const QString &alarm);
private slots:
void setModified(const bool modified);

View File

@ -84,6 +84,14 @@ JSON::Group *Dashboard::getGroup(const int index)
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)
{
if (index < m_compassWidgets.count())

View File

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

View File

@ -21,3 +21,60 @@
*/
#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
#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

View File

@ -29,6 +29,9 @@
using namespace Widgets;
/**
* Configures the compass widget style & the signals/slots with the dashboard module
*/
Compass::Compass(const int index)
: m_index(index)
{
@ -36,32 +39,43 @@ Compass::Compass(const int index)
if (m_index < 0)
return;
// clang-format off
// Configure compass
m_compass.setScale(0, 360);
m_compass.setNeedle(
new QwtCompassMagnetNeedle(QwtCompassMagnetNeedle::TriangleStyle));
m_compass.setLineWidth(2);
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
m_layout.addWidget(&m_compass);
m_layout.setContentsMargins(24, 24, 24, 24);
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
connect(UI::Dashboard::getInstance(), &UI::Dashboard::updated, this,
&Compass::update);
connect(UI::Dashboard::getInstance(),
&UI::Dashboard::updated,
this, &Compass::update);
// clang-format on
}
/**
* Updates the widget's data
*/
void Compass::update()
{
auto dash = UI::Dashboard::getInstance();
auto data = dash->getCompass(m_index);
// Widget not enabled, do nothing
if (!isEnabled())
return;
if (data)
m_compass.setValue(data->value().toDouble());
// Update compass heading
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;
/**
* Generates the user interface elements & layout
*/
DataGroup::DataGroup(const int index)
: m_index(index)
{
if (m_index >= 0)
{
// clang-format off
createUserInterface();
connect(UI::Dashboard::getInstance(), &UI::Dashboard::updated, this,
&DataGroup::updateUserInterface);
connect(UI::Dashboard::getInstance(),
&UI::Dashboard::updated,
this, &DataGroup::updateUserInterface);
// clang-format on
}
}
/**
* Frees the memory allocated for each label that represents a dataset
*/
DataGroup::~DataGroup()
{
foreach (auto icon, m_icons)
@ -55,6 +64,11 @@ DataGroup::~DataGroup()
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()
{
// Get group pointer
@ -155,6 +169,9 @@ void DataGroup::createUserInterface()
m_dataContainer->setStyleSheet(windwQSS);
}
/**
* Updates the dataset labels corresponding to the group that this widget is visualizing.
*/
void DataGroup::updateUserInterface()
{
// 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
* THE SOFTWARE.
*/
#include "Gauge.h"

View File

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

View File

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