mirror of
https://github.com/Serial-Studio/Serial-Studio.git
synced 2025-01-31 17:42:55 +08:00
Implement LED panel #47
This commit is contained in:
parent
667380d75c
commit
b323daca93
@ -180,12 +180,14 @@ HEADERS += \
|
||||
src/Widgets/Common/AnalogGauge.h \
|
||||
src/Widgets/Common/AttitudeIndicator.h \
|
||||
src/Widgets/Common/BaseWidget.h \
|
||||
src/Widgets/Common/KLed.h \
|
||||
src/Widgets/Compass.h \
|
||||
src/Widgets/DataGroup.h \
|
||||
src/Widgets/FFTPlot.h \
|
||||
src/Widgets/GPS.h \
|
||||
src/Widgets/Gauge.h \
|
||||
src/Widgets/Gyroscope.h \
|
||||
src/Widgets/LEDPanel.h \
|
||||
src/Widgets/MultiPlot.h \
|
||||
src/Widgets/Plot.h \
|
||||
src/Widgets/Terminal.h
|
||||
@ -219,12 +221,14 @@ SOURCES += \
|
||||
src/Widgets/Common/AnalogGauge.cpp \
|
||||
src/Widgets/Common/AttitudeIndicator.cpp \
|
||||
src/Widgets/Common/BaseWidget.cpp \
|
||||
src/Widgets/Common/KLed.cpp \
|
||||
src/Widgets/Compass.cpp \
|
||||
src/Widgets/DataGroup.cpp \
|
||||
src/Widgets/FFTPlot.cpp \
|
||||
src/Widgets/GPS.cpp \
|
||||
src/Widgets/Gauge.cpp \
|
||||
src/Widgets/Gyroscope.cpp \
|
||||
src/Widgets/LEDPanel.cpp \
|
||||
src/Widgets/MultiPlot.cpp \
|
||||
src/Widgets/Plot.cpp \
|
||||
src/Widgets/Terminal.cpp \
|
||||
|
@ -140,5 +140,6 @@
|
||||
<file>qml/JsonEditor/TreeView.qml</file>
|
||||
<file>icons/gps.svg</file>
|
||||
<file>qml/Widgets/Terminal.qml</file>
|
||||
<file>icons/led.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
1
assets/icons/led.svg
Normal file
1
assets/icons/led.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6C7.8 12.16 7 10.63 7 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z"/></svg>
|
After Width: | Height: | Size: 447 B |
@ -173,6 +173,17 @@ Widgets.Window {
|
||||
onCheckedChanged: (index, checked) => Cpp_UI_Dashboard.setMultiplotVisible(index, checked)
|
||||
}
|
||||
|
||||
//
|
||||
// LEDs
|
||||
//
|
||||
ViewOptionsDelegate {
|
||||
title: qsTr("LED Panels")
|
||||
icon: "qrc:/icons/led.svg"
|
||||
count: Cpp_UI_Dashboard.ledCount
|
||||
titles: Cpp_UI_Dashboard.ledTitles
|
||||
onCheckedChanged: (index, checked) => Cpp_UI_Dashboard.setLedVisible(index, checked)
|
||||
}
|
||||
|
||||
//
|
||||
// FFT
|
||||
//
|
||||
|
@ -112,6 +112,18 @@ Widgets.Window {
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Dataset LED
|
||||
//
|
||||
Label {
|
||||
text: qsTr("Display LED:")
|
||||
} Switch {
|
||||
id: led
|
||||
Layout.leftMargin: -app.spacing
|
||||
checked: Cpp_JSON_Editor.datasetLED(group, dataset)
|
||||
onCheckedChanged: Cpp_JSON_Editor.setDatasetLED(group, dataset, checked)
|
||||
}
|
||||
|
||||
//
|
||||
// Dataset graph
|
||||
//
|
||||
|
@ -204,7 +204,7 @@ Widgets.Window {
|
||||
delegate: Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumWidth: 320
|
||||
Layout.minimumHeight: 400 + 2 * app.spacing
|
||||
Layout.minimumHeight: 420 + 2 * app.spacing
|
||||
|
||||
JsonDatasetDelegate {
|
||||
id: datasetDelegate
|
||||
|
@ -28,8 +28,9 @@ using namespace JSON;
|
||||
Dataset::Dataset(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_fft(false)
|
||||
, m_graph(false)
|
||||
, m_led(false)
|
||||
, m_log(false)
|
||||
, m_graph(false)
|
||||
, m_title("")
|
||||
, m_value("")
|
||||
, m_units("")
|
||||
@ -50,6 +51,14 @@ bool Dataset::fft() const
|
||||
return m_fft;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return @c true if the UI should generate a LED of this dataset
|
||||
*/
|
||||
bool Dataset::led() const
|
||||
{
|
||||
return m_led;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return @c true if the UI should generate a logarithmic plot of this dataset
|
||||
*/
|
||||
@ -151,6 +160,7 @@ bool Dataset::read(const QJsonObject &object)
|
||||
if (!object.isEmpty())
|
||||
{
|
||||
auto fft = object.value("fft").toVariant().toBool();
|
||||
auto led = object.value("led").toVariant().toBool();
|
||||
auto log = object.value("log").toVariant().toBool();
|
||||
auto graph = object.value("g").toVariant().toBool();
|
||||
auto title = object.value("t").toVariant().toString();
|
||||
@ -182,6 +192,7 @@ bool Dataset::read(const QJsonObject &object)
|
||||
m_min = min;
|
||||
m_max = max;
|
||||
m_fft = fft;
|
||||
m_led = led;
|
||||
m_log = log;
|
||||
m_graph = graph;
|
||||
m_title = title;
|
||||
|
@ -91,6 +91,7 @@ public:
|
||||
Dataset(QObject *parent = nullptr);
|
||||
|
||||
bool fft() const;
|
||||
bool led() const;
|
||||
bool log() const;
|
||||
bool graph() const;
|
||||
double min() const;
|
||||
@ -107,8 +108,9 @@ public:
|
||||
|
||||
private:
|
||||
bool m_fft;
|
||||
bool m_graph;
|
||||
bool m_led;
|
||||
bool m_log;
|
||||
bool m_graph;
|
||||
|
||||
QString m_title;
|
||||
QString m_value;
|
||||
|
@ -324,6 +324,7 @@ bool Editor::saveJsonFile()
|
||||
dataset.insert("t", datasetTitle(i, j));
|
||||
dataset.insert("u", datasetUnits(i, j));
|
||||
dataset.insert("g", datasetGraph(i, j));
|
||||
dataset.insert("led", datasetLED(i, j));
|
||||
dataset.insert("w", datasetWidget(i, j));
|
||||
dataset.insert("fft", datasetFftPlot(i, j));
|
||||
dataset.insert("log", datasetLogPlot(i, j));
|
||||
@ -458,6 +459,22 @@ int Editor::datasetIndex(const int group, const int dataset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns @c true if Serial Studio should generate a LED with the given
|
||||
* @a dataset (which is contained by the specified @a group).
|
||||
*
|
||||
* @param group index of the group in which the dataset belongs
|
||||
* @param dataset index of the dataset
|
||||
*/
|
||||
bool Editor::datasetLED(const int group, const int dataset)
|
||||
{
|
||||
auto set = getDataset(group, dataset);
|
||||
if (set)
|
||||
return set->led();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns @c true if Serial Studio should graph the data of the given
|
||||
* @a dataset (which is contained by the specified @a group).
|
||||
@ -758,6 +775,7 @@ void Editor::openJsonFile(const QString &path)
|
||||
// Register dataset with C++ model
|
||||
addDataset(group);
|
||||
setDatasetGraph(group, dataset, jsonDataset.value("g").toBool());
|
||||
setDatasetLED(group, dataset, jsonDataset.value("led").toBool());
|
||||
setDatasetTitle(group, dataset, jsonDataset.value("t").toString());
|
||||
setDatasetUnits(group, dataset, jsonDataset.value("u").toString());
|
||||
setDatasetFftPlot(group, dataset, jsonDataset.value("fft").toBool());
|
||||
@ -1153,6 +1171,22 @@ void Editor::setDatasetIndex(const int group, const int dataset, const int frame
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the @a generateLED flag of the given @a dataset.
|
||||
*
|
||||
* @param group index of the group in which the dataset belongs
|
||||
* @param dataset index of the dataset
|
||||
*/
|
||||
void Editor::setDatasetLED(const int group, const int dataset, const bool generateLED)
|
||||
{
|
||||
auto set = getDataset(group, dataset);
|
||||
if (set)
|
||||
{
|
||||
set->m_led = generateLED;
|
||||
emit datasetChanged(group, dataset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the @a generateGraph flag of the given @a dataset.
|
||||
*
|
||||
|
@ -115,6 +115,7 @@ public:
|
||||
Q_INVOKABLE int groupWidgetIndex(const int group);
|
||||
|
||||
Q_INVOKABLE int datasetIndex(const int group, const int dataset);
|
||||
Q_INVOKABLE bool datasetLED(const int group, const int dataset);
|
||||
Q_INVOKABLE bool datasetGraph(const int group, const int dataset);
|
||||
Q_INVOKABLE bool datasetFftPlot(const int group, const int dataset);
|
||||
Q_INVOKABLE bool datasetLogPlot(const int group, const int dataset);
|
||||
@ -151,6 +152,7 @@ public slots:
|
||||
void setDatasetTitle(const int group, const int dataset, const QString &title);
|
||||
void setDatasetUnits(const int group, const int dataset, const QString &units);
|
||||
void setDatasetIndex(const int group, const int dataset, const int frameIndex);
|
||||
void setDatasetLED(const int group, const int dataset, const bool generateLED);
|
||||
void setDatasetGraph(const int group, const int dataset, const bool generateGraph);
|
||||
void setDatasetFftPlot(const int group, const int dataset, const bool generateFft);
|
||||
void setDatasetLogPlot(const int group, const int dataset, const bool generateLog);
|
||||
|
@ -31,6 +31,11 @@
|
||||
|
||||
#include "Dataset.h"
|
||||
|
||||
namespace UI
|
||||
{
|
||||
class Dashboard;
|
||||
}
|
||||
|
||||
namespace JSON
|
||||
{
|
||||
/**
|
||||
@ -89,6 +94,7 @@ private:
|
||||
QVector<Dataset *> m_datasets;
|
||||
|
||||
friend class Editor;
|
||||
friend class UI::Dashboard;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -77,6 +77,7 @@ QFont Dashboard::monoFont() const
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
JSON::Group *Dashboard::getLED(const int index) { return getGroupWidget(m_ledWidgets, index); }
|
||||
JSON::Group *Dashboard::getGPS(const int index) { return getGroupWidget(m_gpsWidgets, index); }
|
||||
JSON::Dataset *Dashboard::getBar(const int index) { return getDatasetWidget(m_barWidgets, index); }
|
||||
JSON::Dataset *Dashboard::getFFT(const int index) { return getDatasetWidget(m_fftWidgets, index); }
|
||||
@ -143,7 +144,9 @@ bool Dashboard::frameValid() const
|
||||
int Dashboard::totalWidgetCount() const
|
||||
{
|
||||
// clang-format off
|
||||
const int count = gpsCount() +
|
||||
const int count =
|
||||
gpsCount() +
|
||||
ledCount() +
|
||||
barCount() +
|
||||
fftCount() +
|
||||
plotCount() +
|
||||
@ -160,6 +163,7 @@ int Dashboard::totalWidgetCount() const
|
||||
|
||||
// clang-format off
|
||||
int Dashboard::gpsCount() const { return m_gpsWidgets.count(); }
|
||||
int Dashboard::ledCount() const { return m_ledWidgets.count(); }
|
||||
int Dashboard::barCount() const { return m_barWidgets.count(); }
|
||||
int Dashboard::fftCount() const { return m_fftWidgets.count(); }
|
||||
int Dashboard::plotCount() const { return m_plotWidgets.count(); }
|
||||
@ -188,15 +192,16 @@ QVector<QString> Dashboard::widgetTitles() const
|
||||
|
||||
// clang-format off
|
||||
return groupTitles() +
|
||||
multiPlotTitles() +
|
||||
fftTitles() +
|
||||
plotTitles() +
|
||||
barTitles() +
|
||||
gaugeTitles() +
|
||||
compassTitles() +
|
||||
gyroscopeTitles() +
|
||||
accelerometerTitles() +
|
||||
gpsTitles();
|
||||
multiPlotTitles() +
|
||||
ledTitles() +
|
||||
fftTitles() +
|
||||
plotTitles() +
|
||||
barTitles() +
|
||||
gaugeTitles() +
|
||||
compassTitles() +
|
||||
gyroscopeTitles() +
|
||||
accelerometerTitles() +
|
||||
gpsTitles();
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
@ -235,8 +240,13 @@ int Dashboard::relativeIndex(const int globalIndex) const
|
||||
if (index < multiPlotCount())
|
||||
return index;
|
||||
|
||||
// Check if we should return FFT widget
|
||||
// Check if we should return LED widget
|
||||
index -= multiPlotCount();
|
||||
if (index < ledCount())
|
||||
return index;
|
||||
|
||||
// Check if we should return FFT widget
|
||||
index -= ledCount();
|
||||
if (index < fftCount())
|
||||
return index;
|
||||
|
||||
@ -333,6 +343,9 @@ bool Dashboard::widgetVisible(const int globalIndex) const
|
||||
case WidgetType::GPS:
|
||||
visible = gpsVisible(index);
|
||||
break;
|
||||
case WidgetType::LED:
|
||||
visible = ledVisible(index);
|
||||
break;
|
||||
default:
|
||||
visible = false;
|
||||
break;
|
||||
@ -391,6 +404,9 @@ QString Dashboard::widgetIcon(const int globalIndex) const
|
||||
case WidgetType::GPS:
|
||||
return "qrc:/icons/gps.svg";
|
||||
break;
|
||||
case WidgetType::LED:
|
||||
return "qrc:/icons/led.svg";
|
||||
break;
|
||||
default:
|
||||
return "qrc:/icons/close.svg";
|
||||
break;
|
||||
@ -411,7 +427,8 @@ QString Dashboard::widgetIcon(const int globalIndex) const
|
||||
* - @c WidgetType::Compass
|
||||
* - @c WidgetType::Gyroscope
|
||||
* - @c WidgetType::Accelerometer
|
||||
* - @c WidgetType::Map
|
||||
* - @c WidgetType::GPS
|
||||
* - @c WidgetType::LED
|
||||
*
|
||||
* To simplify operations and user interface generation in QML, this class represents
|
||||
* the widgets in two manners:
|
||||
@ -447,8 +464,13 @@ UI::Dashboard::WidgetType Dashboard::widgetType(const int globalIndex) const
|
||||
if (index < multiPlotCount())
|
||||
return WidgetType::MultiPlot;
|
||||
|
||||
// Check if we should return FFT widget
|
||||
// Check if we should return LED widget
|
||||
index -= multiPlotCount();
|
||||
if (index < ledCount())
|
||||
return WidgetType::LED;
|
||||
|
||||
// Check if we should return FFT widget
|
||||
index -= ledCount();
|
||||
if (index < fftCount())
|
||||
return WidgetType::FFT;
|
||||
|
||||
@ -499,6 +521,7 @@ UI::Dashboard::WidgetType Dashboard::widgetType(const int globalIndex) const
|
||||
bool Dashboard::barVisible(const int index) const { return getVisibility(m_barVisibility, index); }
|
||||
bool Dashboard::fftVisible(const int index) const { return getVisibility(m_fftVisibility, index); }
|
||||
bool Dashboard::gpsVisible(const int index) const { return getVisibility(m_gpsVisibility, index); }
|
||||
bool Dashboard::ledVisible(const int index) const { return getVisibility(m_ledVisibility, index); }
|
||||
bool Dashboard::plotVisible(const int index) const { return getVisibility(m_plotVisibility, index); }
|
||||
bool Dashboard::groupVisible(const int index) const { return getVisibility(m_groupVisibility, index); }
|
||||
bool Dashboard::gaugeVisible(const int index) const { return getVisibility(m_gaugeVisibility, index); }
|
||||
@ -514,6 +537,7 @@ bool Dashboard::accelerometerVisible(const int index) const { return getVisibili
|
||||
|
||||
// clang-format off
|
||||
QVector<QString> Dashboard::gpsTitles() const { return groupTitles(m_gpsWidgets); }
|
||||
QVector<QString> Dashboard::ledTitles() const { return groupTitles(m_ledWidgets); }
|
||||
QVector<QString> Dashboard::groupTitles() const { return groupTitles(m_groupWidgets); }
|
||||
QVector<QString> Dashboard::barTitles() const { return datasetTitles(m_barWidgets); }
|
||||
QVector<QString> Dashboard::fftTitles() const { return datasetTitles(m_fftWidgets); }
|
||||
@ -559,6 +583,7 @@ void Dashboard::setPoints(const int points)
|
||||
void Dashboard::setBarVisible(const int i, const bool v) { setVisibility(m_barVisibility, i, v); }
|
||||
void Dashboard::setFFTVisible(const int i, const bool v) { setVisibility(m_fftVisibility, i, v); }
|
||||
void Dashboard::setGpsVisible(const int i, const bool v) { setVisibility(m_gpsVisibility, i, v); }
|
||||
void Dashboard::setLedVisible(const int i, const bool v) { setVisibility(m_ledVisibility, i, v); }
|
||||
void Dashboard::setPlotVisible(const int i, const bool v) { setVisibility(m_plotVisibility, i, v); }
|
||||
void Dashboard::setGroupVisible(const int i, const bool v) { setVisibility(m_groupVisibility, i, v); }
|
||||
void Dashboard::setGaugeVisible(const int i, const bool v) { setVisibility(m_gaugeVisibility, i, v); }
|
||||
@ -590,6 +615,7 @@ void Dashboard::resetData()
|
||||
m_barWidgets.clear();
|
||||
m_fftWidgets.clear();
|
||||
m_gpsWidgets.clear();
|
||||
m_ledWidgets.clear();
|
||||
m_plotWidgets.clear();
|
||||
m_gaugeWidgets.clear();
|
||||
m_groupWidgets.clear();
|
||||
@ -602,6 +628,7 @@ void Dashboard::resetData()
|
||||
m_barVisibility.clear();
|
||||
m_fftVisibility.clear();
|
||||
m_gpsVisibility.clear();
|
||||
m_ledVisibility.clear();
|
||||
m_plotVisibility.clear();
|
||||
m_gaugeVisibility.clear();
|
||||
m_groupVisibility.clear();
|
||||
@ -634,6 +661,7 @@ void Dashboard::updateData()
|
||||
int barC = barCount();
|
||||
int fftC = fftCount();
|
||||
int mapC = gpsCount();
|
||||
int ledC = ledCount();
|
||||
int plotC = plotCount();
|
||||
int groupC = groupCount();
|
||||
int gaugeC = gaugeCount();
|
||||
@ -654,6 +682,7 @@ void Dashboard::updateData()
|
||||
m_barWidgets.clear();
|
||||
m_fftWidgets.clear();
|
||||
m_gpsWidgets.clear();
|
||||
m_ledWidgets.clear();
|
||||
m_plotWidgets.clear();
|
||||
m_gaugeWidgets.clear();
|
||||
m_groupWidgets.clear();
|
||||
@ -670,6 +699,7 @@ void Dashboard::updateData()
|
||||
|
||||
// Update widget vectors
|
||||
m_fftWidgets = getFFTWidgets();
|
||||
m_ledWidgets = getLEDWidgets();
|
||||
m_plotWidgets = getPlotWidgets();
|
||||
m_groupWidgets = getWidgetGroups("");
|
||||
m_gpsWidgets = getWidgetGroups("map");
|
||||
@ -697,6 +727,7 @@ void Dashboard::updateData()
|
||||
regenerateWidgets |= (barC != barCount());
|
||||
regenerateWidgets |= (fftC != fftCount());
|
||||
regenerateWidgets |= (mapC != gpsCount());
|
||||
regenerateWidgets |= (ledC != ledCount());
|
||||
regenerateWidgets |= (plotC != plotCount());
|
||||
regenerateWidgets |= (gaugeC != gaugeCount());
|
||||
regenerateWidgets |= (groupC != groupCount());
|
||||
@ -711,6 +742,7 @@ void Dashboard::updateData()
|
||||
m_barVisibility.clear();
|
||||
m_fftVisibility.clear();
|
||||
m_gpsVisibility.clear();
|
||||
m_ledVisibility.clear();
|
||||
m_plotVisibility.clear();
|
||||
m_gaugeVisibility.clear();
|
||||
m_groupVisibility.clear();
|
||||
@ -726,6 +758,8 @@ void Dashboard::updateData()
|
||||
m_fftVisibility.append(true);
|
||||
for (i = 0; i < gpsCount(); ++i)
|
||||
m_gpsVisibility.append(true);
|
||||
for (i = 0; i < ledCount(); ++i)
|
||||
m_ledVisibility.append(true);
|
||||
for (i = 0; i < plotCount(); ++i)
|
||||
m_plotVisibility.append(true);
|
||||
for (i = 0; i < gaugeCount(); ++i)
|
||||
@ -843,6 +877,33 @@ void Dashboard::processLatestJSON(const JFI_Object &frameInfo)
|
||||
// Widget utility functions
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a group with all the datasets that need to be shown in the LED status panel.
|
||||
*
|
||||
* @note We return a vector with a single group item because we want to display a title on
|
||||
* the window without breaking the current software architecture.
|
||||
*/
|
||||
QVector<JSON::Group *> Dashboard::getLEDWidgets() const
|
||||
{
|
||||
QVector<JSON::Dataset *> widgets;
|
||||
foreach (auto group, m_latestFrame.groups())
|
||||
{
|
||||
foreach (auto dataset, group->datasets())
|
||||
{
|
||||
if (dataset->led())
|
||||
widgets.append(dataset);
|
||||
}
|
||||
}
|
||||
|
||||
JSON::Group *group = new JSON::Group();
|
||||
group->m_title = tr("Status Panel");
|
||||
group->m_datasets = widgets;
|
||||
|
||||
QVector<JSON::Group *> groups;
|
||||
groups.append(group);
|
||||
return groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a vector with all the datasets that need to be shown in the FFT widgets.
|
||||
*/
|
||||
|
@ -78,6 +78,9 @@ class Dashboard : public QObject
|
||||
Q_PROPERTY(int gpsCount
|
||||
READ gpsCount
|
||||
NOTIFY widgetCountChanged)
|
||||
Q_PROPERTY(int ledCount
|
||||
READ ledCount
|
||||
NOTIFY widgetCountChanged)
|
||||
Q_PROPERTY(int barCount
|
||||
READ barCount
|
||||
NOTIFY widgetCountChanged)
|
||||
@ -108,6 +111,9 @@ class Dashboard : public QObject
|
||||
Q_PROPERTY(QVector<QString> gpsTitles
|
||||
READ gpsTitles
|
||||
NOTIFY widgetCountChanged)
|
||||
Q_PROPERTY(QVector<QString> ledTitles
|
||||
READ ledTitles
|
||||
NOTIFY widgetCountChanged)
|
||||
Q_PROPERTY(QVector<QString> barTitles
|
||||
READ barTitles
|
||||
NOTIFY widgetCountChanged)
|
||||
@ -158,6 +164,7 @@ public:
|
||||
Gyroscope,
|
||||
Accelerometer,
|
||||
GPS,
|
||||
LED,
|
||||
Unknown
|
||||
};
|
||||
Q_ENUM(WidgetType)
|
||||
@ -165,6 +172,7 @@ public:
|
||||
static Dashboard *getInstance();
|
||||
|
||||
QFont monoFont() const;
|
||||
JSON::Group *getLED(const int index);
|
||||
JSON::Group *getGPS(const int index);
|
||||
JSON::Dataset *getFFT(const int index);
|
||||
JSON::Dataset *getBar(const int index);
|
||||
@ -182,6 +190,7 @@ public:
|
||||
|
||||
int totalWidgetCount() const;
|
||||
int gpsCount() const;
|
||||
int ledCount() const;
|
||||
int fftCount() const;
|
||||
int barCount() const;
|
||||
int plotCount() const;
|
||||
@ -202,6 +211,7 @@ public:
|
||||
Q_INVOKABLE bool barVisible(const int index) const;
|
||||
Q_INVOKABLE bool fftVisible(const int index) const;
|
||||
Q_INVOKABLE bool gpsVisible(const int index) const;
|
||||
Q_INVOKABLE bool ledVisible(const int index) const;
|
||||
Q_INVOKABLE bool plotVisible(const int index) const;
|
||||
Q_INVOKABLE bool groupVisible(const int index) const;
|
||||
Q_INVOKABLE bool gaugeVisible(const int index) const;
|
||||
@ -213,6 +223,7 @@ public:
|
||||
QVector<QString> barTitles() const;
|
||||
QVector<QString> fftTitles() const;
|
||||
QVector<QString> gpsTitles() const;
|
||||
QVector<QString> ledTitles() const;
|
||||
QVector<QString> plotTitles() const;
|
||||
QVector<QString> groupTitles() const;
|
||||
QVector<QString> gaugeTitles() const;
|
||||
@ -230,6 +241,7 @@ public slots:
|
||||
void setBarVisible(const int index, const bool visible);
|
||||
void setFFTVisible(const int index, const bool visible);
|
||||
void setGpsVisible(const int index, const bool visible);
|
||||
void setLedVisible(const int index, const bool visible);
|
||||
void setPlotVisible(const int index, const bool visible);
|
||||
void setGroupVisible(const int index, const bool visible);
|
||||
void setGaugeVisible(const int index, const bool visible);
|
||||
@ -247,6 +259,7 @@ private slots:
|
||||
private:
|
||||
Dashboard();
|
||||
|
||||
QVector<JSON::Group *> getLEDWidgets() const;
|
||||
QVector<JSON::Dataset *> getFFTWidgets() const;
|
||||
QVector<JSON::Dataset *> getPlotWidgets() const;
|
||||
QVector<JSON::Group *> getWidgetGroups(const QString &handle) const;
|
||||
@ -272,6 +285,7 @@ private:
|
||||
QVector<bool> m_barVisibility;
|
||||
QVector<bool> m_fftVisibility;
|
||||
QVector<bool> m_gpsVisibility;
|
||||
QVector<bool> m_ledVisibility;
|
||||
QVector<bool> m_plotVisibility;
|
||||
QVector<bool> m_groupVisibility;
|
||||
QVector<bool> m_gaugeVisibility;
|
||||
@ -286,6 +300,7 @@ private:
|
||||
QVector<JSON::Dataset *> m_gaugeWidgets;
|
||||
QVector<JSON::Dataset *> m_compassWidgets;
|
||||
|
||||
QVector<JSON::Group *> m_ledWidgets;
|
||||
QVector<JSON::Group *> m_gpsWidgets;
|
||||
QVector<JSON::Group *> m_groupWidgets;
|
||||
QVector<JSON::Group *> m_multiPlotWidgets;
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <Widgets/Gauge.h>
|
||||
#include <Widgets/Compass.h>
|
||||
#include <Widgets/FFTPlot.h>
|
||||
#include <Widgets/LEDPanel.h>
|
||||
#include <Widgets/DataGroup.h>
|
||||
#include <Widgets/Gyroscope.h>
|
||||
#include <Widgets/MultiPlot.h>
|
||||
@ -276,6 +277,9 @@ void WidgetLoader::setWidgetIndex(const int index)
|
||||
case UI::Dashboard::WidgetType::GPS:
|
||||
m_widget = new GPS(relativeIndex());
|
||||
break;
|
||||
case UI::Dashboard::WidgetType::LED:
|
||||
m_widget = new LEDPanel(relativeIndex());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
274
src/Widgets/Common/KLed.cpp
Normal file
274
src/Widgets/Common/KLed.cpp
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 1998 Jörg Habenicht <j.habenicht@europemail.com>
|
||||
SPDX-FileCopyrightText: 2010 Christoph Feck <cfeck@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "kled.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <QPainter>
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
|
||||
class KLedPrivate
|
||||
{
|
||||
public:
|
||||
int darkFactor = 300;
|
||||
QColor color;
|
||||
KLed::State state = KLed::On;
|
||||
KLed::Look look = KLed::Raised;
|
||||
KLed::Shape shape = KLed::Circular;
|
||||
|
||||
QPixmap cachedPixmap[2]; // for both states
|
||||
};
|
||||
|
||||
KLed::KLed(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, d(new KLedPrivate)
|
||||
{
|
||||
setColor(Qt::green);
|
||||
updateAccessibleName();
|
||||
}
|
||||
|
||||
KLed::KLed(const QColor &color, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, d(new KLedPrivate)
|
||||
{
|
||||
setColor(color);
|
||||
updateAccessibleName();
|
||||
}
|
||||
|
||||
KLed::KLed(const QColor &color, State state, Look look, Shape shape, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, d(new KLedPrivate)
|
||||
{
|
||||
d->state = (state == Off ? Off : On);
|
||||
d->look = look;
|
||||
d->shape = shape;
|
||||
|
||||
setColor(color);
|
||||
updateAccessibleName();
|
||||
}
|
||||
|
||||
KLed::~KLed() = default;
|
||||
|
||||
KLed::State KLed::state() const
|
||||
{
|
||||
return d->state;
|
||||
}
|
||||
|
||||
KLed::Shape KLed::shape() const
|
||||
{
|
||||
return d->shape;
|
||||
}
|
||||
|
||||
QColor KLed::color() const
|
||||
{
|
||||
return d->color;
|
||||
}
|
||||
|
||||
KLed::Look KLed::look() const
|
||||
{
|
||||
return d->look;
|
||||
}
|
||||
|
||||
void KLed::setState(State state)
|
||||
{
|
||||
if (d->state == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
d->state = (state == Off ? Off : On);
|
||||
updateCachedPixmap();
|
||||
updateAccessibleName();
|
||||
}
|
||||
|
||||
void KLed::setShape(Shape shape)
|
||||
{
|
||||
if (d->shape == shape)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
d->shape = shape;
|
||||
updateCachedPixmap();
|
||||
}
|
||||
|
||||
void KLed::setColor(const QColor &color)
|
||||
{
|
||||
if (d->color == color)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
d->color = color;
|
||||
updateCachedPixmap();
|
||||
}
|
||||
|
||||
void KLed::setDarkFactor(int darkFactor)
|
||||
{
|
||||
if (d->darkFactor == darkFactor)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
d->darkFactor = darkFactor;
|
||||
updateCachedPixmap();
|
||||
}
|
||||
|
||||
int KLed::darkFactor() const
|
||||
{
|
||||
return d->darkFactor;
|
||||
}
|
||||
|
||||
void KLed::setLook(Look look)
|
||||
{
|
||||
if (d->look == look)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
d->look = look;
|
||||
updateCachedPixmap();
|
||||
}
|
||||
|
||||
void KLed::toggle()
|
||||
{
|
||||
d->state = (d->state == On ? Off : On);
|
||||
updateCachedPixmap();
|
||||
updateAccessibleName();
|
||||
}
|
||||
|
||||
void KLed::on()
|
||||
{
|
||||
setState(On);
|
||||
}
|
||||
|
||||
void KLed::off()
|
||||
{
|
||||
setState(Off);
|
||||
}
|
||||
|
||||
void KLed::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
updateCachedPixmap();
|
||||
}
|
||||
|
||||
QSize KLed::sizeHint() const
|
||||
{
|
||||
QStyleOption option;
|
||||
option.initFrom(this);
|
||||
int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, &option, this);
|
||||
return QSize(iconSize, iconSize);
|
||||
}
|
||||
|
||||
QSize KLed::minimumSizeHint() const
|
||||
{
|
||||
return QSize(32, 32);
|
||||
}
|
||||
|
||||
void KLed::updateAccessibleName()
|
||||
{
|
||||
#ifndef QT_NO_ACCESSIBILITY
|
||||
QString onName = tr("LED on", "Accessible name of a Led whose state is on");
|
||||
QString offName = tr("LED off", "Accessible name of a Led whose state is off");
|
||||
QString lastName = accessibleName();
|
||||
|
||||
if (lastName.isEmpty() || lastName == onName || lastName == offName)
|
||||
{
|
||||
// Accessible name has not been manually set.
|
||||
|
||||
setAccessibleName(d->state == On ? onName : offName);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void KLed::updateCachedPixmap()
|
||||
{
|
||||
d->cachedPixmap[Off] = QPixmap();
|
||||
d->cachedPixmap[On] = QPixmap();
|
||||
update();
|
||||
}
|
||||
|
||||
void KLed::paintEvent(QPaintEvent *)
|
||||
{
|
||||
if (!d->cachedPixmap[d->state].isNull())
|
||||
{
|
||||
QPainter painter(this);
|
||||
painter.drawPixmap(1, 1, d->cachedPixmap[d->state]);
|
||||
return;
|
||||
}
|
||||
|
||||
QSize size(width() - 2, height() - 2);
|
||||
if (d->shape == Circular)
|
||||
{
|
||||
// Make sure the LED is round
|
||||
const int dim = qMin(width(), height()) - 2;
|
||||
size = QSize(dim, dim);
|
||||
}
|
||||
QPointF center(size.width() / 2.0, size.height() / 2.0);
|
||||
const int smallestSize = qMin(size.width(), size.height());
|
||||
QPainter painter;
|
||||
|
||||
QImage image(size, QImage::Format_ARGB32_Premultiplied);
|
||||
image.fill(0);
|
||||
|
||||
QRadialGradient fillGradient(center, smallestSize / 2.0,
|
||||
QPointF(center.x(), size.height() / 3.0));
|
||||
const QColor fillColor = d->state != Off ? d->color : d->color.darker(d->darkFactor);
|
||||
fillGradient.setColorAt(0.0, fillColor.lighter(250));
|
||||
fillGradient.setColorAt(0.5, fillColor.lighter(130));
|
||||
fillGradient.setColorAt(1.0, fillColor);
|
||||
|
||||
QConicalGradient borderGradient(center, d->look == Sunken ? 90 : -90);
|
||||
QColor borderColor = palette().color(QPalette::Dark);
|
||||
if (d->state == On)
|
||||
{
|
||||
QColor glowOverlay = fillColor;
|
||||
glowOverlay.setAlpha(80);
|
||||
|
||||
// This isn't the fastest way, but should be "fast enough".
|
||||
// It's also the only safe way to use QPainter::CompositionMode
|
||||
QImage img(1, 1, QImage::Format_ARGB32_Premultiplied);
|
||||
QPainter p(&img);
|
||||
QColor start = borderColor;
|
||||
start.setAlpha(255); // opaque
|
||||
p.fillRect(0, 0, 1, 1, start);
|
||||
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
p.fillRect(0, 0, 1, 1, glowOverlay);
|
||||
p.end();
|
||||
|
||||
borderColor = img.pixel(0, 0);
|
||||
}
|
||||
borderGradient.setColorAt(0.2, borderColor);
|
||||
borderGradient.setColorAt(0.5, palette().color(QPalette::Light));
|
||||
borderGradient.setColorAt(0.8, borderColor);
|
||||
|
||||
painter.begin(&image);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setBrush(d->look == Flat ? QBrush(fillColor) : QBrush(fillGradient));
|
||||
const QBrush penBrush
|
||||
= (d->look == Flat) ? QBrush(borderColor) : QBrush(borderGradient);
|
||||
const qreal penWidth = smallestSize / 8.0;
|
||||
painter.setPen(QPen(penBrush, penWidth));
|
||||
QRectF r(penWidth / 2.0, penWidth / 2.0, size.width() - penWidth,
|
||||
size.height() - penWidth);
|
||||
if (d->shape == Rectangular)
|
||||
{
|
||||
painter.drawRect(r);
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.drawEllipse(r);
|
||||
}
|
||||
painter.end();
|
||||
|
||||
d->cachedPixmap[d->state] = QPixmap::fromImage(image);
|
||||
painter.begin(this);
|
||||
painter.drawPixmap(1, 1, d->cachedPixmap[d->state]);
|
||||
painter.end();
|
||||
}
|
258
src/Widgets/Common/KLed.h
Normal file
258
src/Widgets/Common/KLed.h
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 1998 Jörg Habenicht <j.habenicht@europemail.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KLED_H
|
||||
#define KLED_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <memory>
|
||||
|
||||
class QColor;
|
||||
|
||||
/**
|
||||
* @class KLed kled.h KLed
|
||||
*
|
||||
* @short An LED widget.
|
||||
*
|
||||
* Displays a round or rectangular light emitting diode.
|
||||
*
|
||||
* It is configurable to arbitrary colors, the two on/off states and three
|
||||
* styles (or "looks");
|
||||
*
|
||||
* It may display itself in a performant flat view, a round view with
|
||||
* light spot or a round view sunken in the screen.
|
||||
*
|
||||
* \image html kled.png "KLed Widget"
|
||||
*
|
||||
* @author Joerg Habenicht, Richard J. Moore (rich@kde.org) 1998, 1999
|
||||
*/
|
||||
class KLed : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(State state READ state WRITE setState)
|
||||
Q_PROPERTY(Shape shape READ shape WRITE setShape)
|
||||
Q_PROPERTY(Look look READ look WRITE setLook)
|
||||
Q_PROPERTY(QColor color READ color WRITE setColor)
|
||||
Q_PROPERTY(int darkFactor READ darkFactor WRITE setDarkFactor)
|
||||
|
||||
public:
|
||||
/**
|
||||
* Status of the light is on/off.
|
||||
* @short LED on/off.
|
||||
*/
|
||||
enum State
|
||||
{
|
||||
Off,
|
||||
On
|
||||
};
|
||||
Q_ENUM(State)
|
||||
|
||||
/**
|
||||
* Shades of the lamp.
|
||||
* @short LED shape
|
||||
*/
|
||||
enum Shape
|
||||
{
|
||||
Rectangular,
|
||||
Circular
|
||||
};
|
||||
Q_ENUM(Shape)
|
||||
|
||||
/**
|
||||
* Displays a flat, round or sunken LED.
|
||||
*
|
||||
* @short LED look.
|
||||
*/
|
||||
enum Look
|
||||
{
|
||||
Flat,
|
||||
Raised,
|
||||
Sunken,
|
||||
};
|
||||
Q_ENUM(Look)
|
||||
|
||||
/**
|
||||
* Constructs a green, round LED widget which will initially
|
||||
* be turned on.
|
||||
*
|
||||
* @param parent The parent widget.
|
||||
*/
|
||||
explicit KLed(QWidget *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Constructs a round LED widget with the supplied color which will
|
||||
* initially be turned on.
|
||||
*
|
||||
* @param color Initial color of the LED.
|
||||
* @param parent The parent widget.
|
||||
* @short Constructor
|
||||
*/
|
||||
explicit KLed(const QColor &color, QWidget *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Constructor with the color, state and look.
|
||||
*
|
||||
* Differs from above only in the parameters, which configure all settings.
|
||||
*
|
||||
* @param color Initial color of the LED.
|
||||
* @param state Sets the State.
|
||||
* @param look Sets the Look.
|
||||
* @param shape Sets the Shape (rectangular or circular).
|
||||
* @param parent The parent widget.
|
||||
* @short Constructor
|
||||
*/
|
||||
KLed(const QColor &color, KLed::State state, KLed::Look look, KLed::Shape shape,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Destroys the LED widget.
|
||||
* @short Destructor
|
||||
*/
|
||||
~KLed() override;
|
||||
|
||||
/**
|
||||
* Returns the current color of the widget.
|
||||
*
|
||||
* @returns LED color
|
||||
* @see setColor()
|
||||
*/
|
||||
QColor color() const;
|
||||
|
||||
/**
|
||||
* Returns the current state of the widget (on/off).
|
||||
* @returns LED state
|
||||
*
|
||||
* @see State
|
||||
*/
|
||||
State state() const;
|
||||
|
||||
/**
|
||||
* Returns the current look of the widget.
|
||||
* @returns LED look
|
||||
*
|
||||
* @see Look
|
||||
*/
|
||||
Look look() const;
|
||||
|
||||
/**
|
||||
* Returns the current shape of the widget.
|
||||
* @returns LED shape
|
||||
*
|
||||
* @see Shape
|
||||
*/
|
||||
Shape shape() const;
|
||||
|
||||
/**
|
||||
* Returns the factor to darken the LED.
|
||||
* @returns dark factor
|
||||
*
|
||||
* @see setDarkFactor()
|
||||
*/
|
||||
int darkFactor() const;
|
||||
|
||||
/**
|
||||
* Set the color of the widget.
|
||||
*
|
||||
* The LED is shown with @p color when in the KLed::On state
|
||||
* or with the darken color in KLed::Off state.
|
||||
*
|
||||
* The widget calls the update() method, so it will
|
||||
* be updated when entering the main event loop.
|
||||
*
|
||||
* @param color New color of the LED.
|
||||
*
|
||||
* @see color() darkFactor()
|
||||
*/
|
||||
void setColor(const QColor &color);
|
||||
|
||||
/**
|
||||
* Sets the state of the widget to On or Off.
|
||||
*
|
||||
* @param state The LED state: on or off.
|
||||
*
|
||||
* @see on() off() toggle()
|
||||
*/
|
||||
void setState(State state);
|
||||
|
||||
/**
|
||||
* Sets the look of the widget.
|
||||
*
|
||||
* The look may be Flat, Raised or Sunken.
|
||||
*
|
||||
* The widget calls the update() method, so it will
|
||||
* be updated when entering the main event loop.
|
||||
*
|
||||
* @param look New look of the LED.
|
||||
*
|
||||
* @see Look
|
||||
*/
|
||||
void setLook(Look look);
|
||||
|
||||
/**
|
||||
* Set the shape of the LED.
|
||||
*
|
||||
* @param shape The LED shape.
|
||||
* @short Set LED shape.
|
||||
*/
|
||||
void setShape(Shape shape);
|
||||
|
||||
/**
|
||||
* Sets the factor to darken the LED in KLed::Off state.
|
||||
*
|
||||
* The @p darkFactor should be greater than 100, otherwise the LED
|
||||
* becomes lighter in KLed::Off state.
|
||||
*
|
||||
* Defaults to 300.
|
||||
*
|
||||
* @param darkFactor Sets the factor to darken the LED.
|
||||
*
|
||||
* @see setColor
|
||||
*/
|
||||
void setDarkFactor(int darkFactor);
|
||||
|
||||
QSize sizeHint() const override;
|
||||
QSize minimumSizeHint() const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
/**
|
||||
* Toggles the state of the led from Off to On or vice versa.
|
||||
*/
|
||||
void toggle();
|
||||
|
||||
/**
|
||||
* Sets the state of the widget to On.
|
||||
*
|
||||
* @see off() toggle() setState()
|
||||
*/
|
||||
void on();
|
||||
|
||||
/**
|
||||
* Sets the state of the widget to Off.
|
||||
*
|
||||
* @see on() toggle() setState()
|
||||
*/
|
||||
void off();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
void resizeEvent(QResizeEvent *) override;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* invalidates caches after property changes and calls update()
|
||||
*/
|
||||
void updateCachedPixmap();
|
||||
|
||||
private:
|
||||
void updateAccessibleName();
|
||||
|
||||
private:
|
||||
std::unique_ptr<class KLedPrivate> const d;
|
||||
};
|
||||
|
||||
#endif
|
274
src/Widgets/LEDPanel.cpp
Normal file
274
src/Widgets/LEDPanel.cpp
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "LEDPanel.h"
|
||||
#include "UI/Dashboard.h"
|
||||
#include "Misc/ThemeManager.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QWheelEvent>
|
||||
#include <QResizeEvent>
|
||||
|
||||
using namespace Widgets;
|
||||
|
||||
/**
|
||||
* Generates the user interface elements & layout
|
||||
*/
|
||||
LEDPanel::LEDPanel(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->ledCount())
|
||||
return;
|
||||
|
||||
// Get group pointer
|
||||
auto group = dash->getLED(m_index);
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
// Generate widget stylesheets
|
||||
auto titleQSS = QSS("color:%1", theme->widgetTextPrimary());
|
||||
|
||||
// Set window palette
|
||||
QPalette windowPalette;
|
||||
windowPalette.setColor(QPalette::Base, theme->widgetWindowBackground());
|
||||
windowPalette.setColor(QPalette::Window, theme->widgetWindowBackground());
|
||||
setPalette(windowPalette);
|
||||
|
||||
// Configure scroll area container
|
||||
m_dataContainer = new QWidget(this);
|
||||
|
||||
// Make the value label larger
|
||||
auto valueFont = dash->monoFont();
|
||||
valueFont.setPixelSize(dash->monoFont().pixelSize() * 1.3);
|
||||
|
||||
// Get LED color list
|
||||
QString color;
|
||||
auto colors = QStringList { "#ff3333", "#ff9933", "#ffff33", "#99ff33",
|
||||
"#33ff33", "#33ff99", "#33ffff", "#3399ff",
|
||||
"#3333ff", "#9933ff", "#ff33ff", "#ff3399" };
|
||||
|
||||
// Configure grid layout
|
||||
m_gridLayout = new QGridLayout(m_dataContainer);
|
||||
m_gridLayout->setSpacing(8);
|
||||
for (int dataset = 0; dataset < group->datasetCount(); ++dataset)
|
||||
{
|
||||
// Create labels
|
||||
m_leds.append(new KLed(m_dataContainer));
|
||||
m_titles.append(new QLabel(m_dataContainer));
|
||||
|
||||
// Get pointers to labels
|
||||
auto led = m_leds.last();
|
||||
auto title = m_titles.last();
|
||||
|
||||
// Set label styles & fonts
|
||||
title->setStyleSheet(titleQSS);
|
||||
title->setFont(dash->monoFont());
|
||||
title->setText(group->getDataset(dataset)->title());
|
||||
|
||||
// Get LED color
|
||||
if (colors.count() > dataset)
|
||||
color = colors.at(dataset);
|
||||
else
|
||||
color = colors.at(colors.count() % dataset);
|
||||
|
||||
// Set LED color & style
|
||||
led->setLook(KLed::Flat);
|
||||
led->setShape(KLed::Rectangular);
|
||||
led->setColor(QColor(color));
|
||||
|
||||
// Calculate column and row
|
||||
int column = 0;
|
||||
int row = dataset;
|
||||
int count = dataset + 1;
|
||||
while (count > 3)
|
||||
{
|
||||
count -= 3;
|
||||
row -= 3;
|
||||
column += 2;
|
||||
}
|
||||
|
||||
// Add label and LED to grid layout
|
||||
m_gridLayout->addWidget(led, row, column);
|
||||
m_gridLayout->addWidget(title, row, column + 1);
|
||||
m_gridLayout->setAlignment(title, Qt::AlignLeft | Qt::AlignVCenter);
|
||||
m_gridLayout->setAlignment(led, Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
}
|
||||
|
||||
// Load layout into container widget
|
||||
m_dataContainer->setLayout(m_gridLayout);
|
||||
|
||||
// Configure scroll area
|
||||
m_scrollArea = new QScrollArea(this);
|
||||
m_scrollArea->setWidgetResizable(true);
|
||||
m_scrollArea->setWidget(m_dataContainer);
|
||||
m_scrollArea->setFrameShape(QFrame::NoFrame);
|
||||
m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
// Configure main layout
|
||||
m_mainLayout = new QVBoxLayout(this);
|
||||
m_mainLayout->addWidget(m_scrollArea);
|
||||
m_mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
setLayout(m_mainLayout);
|
||||
|
||||
// React to dashboard events
|
||||
connect(dash, SIGNAL(updated()), this, SLOT(updateData()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the memory allocated for each label and LED that represents a dataset
|
||||
*/
|
||||
LEDPanel::~LEDPanel()
|
||||
{
|
||||
foreach (auto led, m_leds)
|
||||
delete led;
|
||||
|
||||
foreach (auto title, m_titles)
|
||||
delete title;
|
||||
|
||||
delete m_gridLayout;
|
||||
delete m_scrollArea;
|
||||
delete m_mainLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 widget shall ignore the update request.
|
||||
*/
|
||||
void LEDPanel::updateData()
|
||||
{
|
||||
// Widget not enabled, do nothing
|
||||
if (!isEnabled())
|
||||
return;
|
||||
|
||||
// Get group pointer
|
||||
auto dash = UI::Dashboard::getInstance();
|
||||
auto group = dash->getLED(m_index);
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
// Update labels
|
||||
JSON::Dataset *dataset;
|
||||
for (int i = 0; i < group->datasetCount(); ++i)
|
||||
{
|
||||
dataset = group->getDataset(i);
|
||||
if (dataset)
|
||||
{
|
||||
#ifndef LAZY_WIDGETS
|
||||
m_titles.at(i)->setText(set->title());
|
||||
#endif
|
||||
// Get dataset value (we compare with 0.1 for low voltages)
|
||||
auto value = dataset->value().toDouble();
|
||||
if (qAbs(value) < 0.10)
|
||||
m_leds.at(i)->off();
|
||||
else
|
||||
m_leds.at(i)->on();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the size of the labels when the widget is resized
|
||||
*/
|
||||
void LEDPanel::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
auto width = event->size().width();
|
||||
QFont font = UI::Dashboard::getInstance()->monoFont();
|
||||
font.setPixelSize(qMax(8, width / 24));
|
||||
auto fHeight = QFontMetrics(font).height() * 1.5;
|
||||
|
||||
for (int i = 0; i < m_titles.count(); ++i)
|
||||
{
|
||||
m_titles.at(i)->setFont(font);
|
||||
m_leds.at(i)->setMinimumSize(fHeight, fHeight);
|
||||
}
|
||||
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void LEDPanel::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
class Hack : public QScrollArea
|
||||
{
|
||||
public:
|
||||
using QWidget::wheelEvent;
|
||||
};
|
||||
|
||||
auto hack = static_cast<Hack *>(m_scrollArea);
|
||||
hack->wheelEvent(event);
|
||||
}
|
||||
|
||||
void LEDPanel::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
class Hack : public QScrollArea
|
||||
{
|
||||
public:
|
||||
using QWidget::mouseMoveEvent;
|
||||
};
|
||||
|
||||
auto hack = static_cast<Hack *>(m_scrollArea);
|
||||
hack->mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void LEDPanel::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
class Hack : public QScrollArea
|
||||
{
|
||||
public:
|
||||
using QWidget::mousePressEvent;
|
||||
};
|
||||
|
||||
auto hack = static_cast<Hack *>(m_scrollArea);
|
||||
hack->mousePressEvent(event);
|
||||
}
|
||||
|
||||
void LEDPanel::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
class Hack : public QScrollArea
|
||||
{
|
||||
public:
|
||||
using QWidget::mouseReleaseEvent;
|
||||
};
|
||||
|
||||
auto hack = static_cast<Hack *>(m_scrollArea);
|
||||
hack->mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void LEDPanel::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
class Hack : public QScrollArea
|
||||
{
|
||||
public:
|
||||
using QWidget::mouseDoubleClickEvent;
|
||||
};
|
||||
|
||||
auto hack = static_cast<Hack *>(m_scrollArea);
|
||||
hack->mouseDoubleClickEvent(event);
|
||||
}
|
68
src/Widgets/LEDPanel.h
Normal file
68
src/Widgets/LEDPanel.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef WIDGETS_LEDPANEL_H
|
||||
#define WIDGETS_LEDPANEL_H
|
||||
|
||||
#include <QLabel>
|
||||
#include <QWidget>
|
||||
#include <QGridLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QScrollArea>
|
||||
|
||||
#include "Common/KLed.h"
|
||||
|
||||
namespace Widgets
|
||||
{
|
||||
class LEDPanel : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LEDPanel(const int index = -1);
|
||||
~LEDPanel();
|
||||
|
||||
private slots:
|
||||
void updateData();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
void wheelEvent(QWheelEvent *event);
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void mouseReleaseEvent(QMouseEvent *event);
|
||||
void mouseDoubleClickEvent(QMouseEvent *event);
|
||||
|
||||
private:
|
||||
int m_index;
|
||||
|
||||
QVector<KLed *> m_leds;
|
||||
QVector<QLabel *> m_titles;
|
||||
|
||||
QWidget *m_dataContainer;
|
||||
QVBoxLayout *m_mainLayout;
|
||||
QGridLayout *m_gridLayout;
|
||||
QScrollArea *m_scrollArea;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user