mirror of
https://github.com/CURTLab/LVGLBuilder.git
synced 2025-05-08 19:40:36 +08:00
343 lines
10 KiB
C++
343 lines
10 KiB
C++
#include "LVGLPropertySeries.h"
|
|
|
|
#include <QDialogButtonBox>
|
|
#include <QGridLayout>
|
|
#include <QListWidget>
|
|
#include <QPushButton>
|
|
#include <QToolButton>
|
|
#include <QPixmap>
|
|
#include <QColorDialog>
|
|
#include <QStyledItemDelegate>
|
|
#include <QSpinBox>
|
|
#include <QDialog>
|
|
#include <QJsonArray>
|
|
|
|
#include "LVGLCore.h"
|
|
#include "LVGLObject.h"
|
|
|
|
struct LVGLChartSeries
|
|
{
|
|
QColor color;
|
|
QVector<lv_coord_t> points;
|
|
lv_chart_series_t *ser;
|
|
};
|
|
|
|
class LVGLPropertySeriesDialog : public QDialog
|
|
{
|
|
public:
|
|
LVGLPropertySeriesDialog(QWidget *parent = nullptr);
|
|
|
|
QListWidget *m_seriesList;
|
|
QListWidget *m_dataList;
|
|
QVector<LVGLChartSeries> m_series;
|
|
|
|
friend class LVGLPropertySeries;
|
|
|
|
};
|
|
|
|
class LVGLPropertySeriesDelegate : public QStyledItemDelegate
|
|
{
|
|
LVGLPropertySeriesDialog *m_dialog;
|
|
public:
|
|
LVGLPropertySeriesDelegate(LVGLPropertySeriesDialog *dialog) : m_dialog(dialog) {}
|
|
|
|
QWidget *createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override
|
|
{
|
|
Q_UNUSED(option)
|
|
if (index.isValid()) {
|
|
QSpinBox *widget = new QSpinBox(parent);
|
|
widget->setRange(0, std::min(lvgl.width(), lvgl.height()));
|
|
return widget;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void setEditorData(QWidget* editor, const QModelIndex& index) const override
|
|
{
|
|
if (index.isValid()) {
|
|
QSpinBox *widget = qobject_cast<QSpinBox*>(editor);
|
|
widget->setValue(index.data().toInt());
|
|
}
|
|
}
|
|
|
|
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
|
|
{
|
|
if (index.isValid()) {
|
|
QSpinBox *widget = qobject_cast<QSpinBox*>(editor);
|
|
model->setData(index, widget->value());
|
|
|
|
int idx = m_dialog->m_dataList->currentRow();
|
|
if (idx > -1)
|
|
m_dialog->m_series[m_dialog->m_seriesList->currentRow()].points[idx] = static_cast<lv_coord_t>(widget->value());
|
|
}
|
|
}
|
|
};
|
|
|
|
LVGLPropertySeriesDialog::LVGLPropertySeriesDialog(QWidget *parent)
|
|
: QDialog(parent)
|
|
{
|
|
m_seriesList = new QListWidget;
|
|
m_dataList = new QListWidget;
|
|
m_dataList->setItemDelegate(new LVGLPropertySeriesDelegate(this));
|
|
|
|
QToolButton *color = new QToolButton;
|
|
QPushButton *add1 = new QPushButton("Add series");
|
|
QPushButton *rem1 = new QPushButton("Remove series");
|
|
QPushButton *add2 = new QPushButton("Add point");
|
|
QPushButton *rem2 = new QPushButton("Remove point");
|
|
|
|
QPixmap pix(16, 16);
|
|
pix.fill(Qt::red);
|
|
color->setIcon(QIcon(pix));
|
|
|
|
QDialogButtonBox *box = new QDialogButtonBox(QDialogButtonBox::Ok |
|
|
QDialogButtonBox::Cancel);
|
|
connect(box, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
|
connect(box, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
|
|
|
QGridLayout *layout1 = new QGridLayout;
|
|
layout1->addWidget(add1, 0, 0);
|
|
layout1->addWidget(rem1, 1, 0);
|
|
layout1->addWidget(m_seriesList, 2, 0, 2, 1);
|
|
layout1->addWidget(add2, 0, 1);
|
|
layout1->addWidget(rem2, 1, 1);
|
|
layout1->addWidget(color, 2, 1);
|
|
layout1->addWidget(m_dataList, 3, 1);
|
|
layout1->addWidget(box, 4, 0, 1, 2);
|
|
|
|
add2->setEnabled(false);
|
|
rem2->setEnabled(false);
|
|
color->setEnabled(false);
|
|
|
|
connect(add1, &QPushButton::clicked, [this](bool) {
|
|
QList<int> numbers;
|
|
for (int i = 0; i < m_seriesList->count(); ++i) {
|
|
QString text = m_seriesList->item(i)->text();
|
|
int num = text.mid(text.indexOf(' ') + 1).toInt();
|
|
auto ind = std::lower_bound(numbers.begin(), numbers.end(), num);
|
|
numbers.insert(ind, num);
|
|
}
|
|
int id = 1;
|
|
for (int num:numbers) {
|
|
if (num == id)
|
|
id++;
|
|
else
|
|
break;
|
|
}
|
|
LVGLChartSeries series;
|
|
series.color = Qt::red;
|
|
m_series << series;
|
|
m_seriesList->addItem(QString("Series %1").arg(id));
|
|
});
|
|
connect(rem1, &QPushButton::clicked, [this](bool) {
|
|
int idx = m_seriesList->currentRow();
|
|
if (idx > -1) {
|
|
m_seriesList->takeItem(idx);
|
|
m_series.removeAt(idx);
|
|
}
|
|
});
|
|
connect(m_seriesList, &QListWidget::currentRowChanged, [=](int idx) {
|
|
const bool isValid = (idx >= 0);
|
|
add2->setEnabled(isValid);
|
|
rem2->setEnabled(isValid);
|
|
color->setEnabled(isValid);
|
|
|
|
if (isValid) {
|
|
QPixmap pix(16, 16);
|
|
pix.fill(m_series[idx].color);
|
|
color->setIcon(QIcon(pix));
|
|
|
|
m_dataList->clear();
|
|
for (const auto &p:m_series[idx].points) {
|
|
QListWidgetItem *item = new QListWidgetItem(QString::number(p));
|
|
item->setFlags(item->flags() | Qt::ItemIsEditable);
|
|
m_dataList->addItem(item);
|
|
}
|
|
}
|
|
});
|
|
connect(color, &QPushButton::clicked, [this,color](bool) {
|
|
QColorDialog dialog(this);
|
|
int idx = m_seriesList->currentRow();
|
|
dialog.setCurrentColor(m_series[idx].color);
|
|
if (dialog.exec() == QDialog::Accepted) {
|
|
QPixmap pix(16, 16);
|
|
pix.fill(dialog.selectedColor());
|
|
color->setIcon(QIcon(pix));
|
|
m_series[idx].color = dialog.selectedColor();
|
|
}
|
|
});
|
|
connect(add2, &QPushButton::clicked, [this](bool) {
|
|
m_series[m_seriesList->currentRow()].points << 0;
|
|
QListWidgetItem *item = new QListWidgetItem("0");
|
|
item->setFlags(item->flags() | Qt::ItemIsEditable);
|
|
m_dataList->addItem(item);
|
|
});
|
|
connect(rem2, &QPushButton::clicked, [this](bool) {
|
|
int idx = m_seriesList->currentRow();
|
|
if (idx > -1) {
|
|
m_dataList->takeItem(idx);
|
|
m_series[m_seriesList->currentRow()].points.removeAt(idx);
|
|
}
|
|
});
|
|
|
|
setLayout(layout1);
|
|
}
|
|
|
|
LVGLPropertySeries::LVGLPropertySeries(LVGLProperty *parent)
|
|
: LVGLProperty(parent)
|
|
{
|
|
}
|
|
|
|
QString LVGLPropertySeries::name() const
|
|
{
|
|
return "Series";
|
|
}
|
|
|
|
bool LVGLPropertySeries::hasEditor() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
QWidget *LVGLPropertySeries::editor(QWidget *parent)
|
|
{
|
|
m_widget = new LVGLPropertySeriesDialog(parent);
|
|
return m_widget;
|
|
}
|
|
|
|
void LVGLPropertySeries::updateEditor(LVGLObject *obj)
|
|
{
|
|
lv_obj_t *chart = obj->obj();
|
|
Q_ASSERT(lv_debug_check_obj_type(chart, "lv_chart"));
|
|
|
|
lv_chart_ext_t *ext = reinterpret_cast<lv_chart_ext_t*>(lv_obj_get_ext_attr(chart));
|
|
|
|
lv_chart_series_t *ser;
|
|
size_t i = 1;
|
|
for (ser = reinterpret_cast<lv_chart_series_t*>(lv_ll_get_tail(&ext->series_ll));
|
|
ser != nullptr;
|
|
ser = reinterpret_cast<lv_chart_series_t*>(lv_ll_get_prev(&ext->series_ll, ser)), ++i)
|
|
{
|
|
LVGLChartSeries series;
|
|
series.color = lvgl.toColor(ser->color);
|
|
const uint16_t ctx = ser->start_point == 0 ? lv_chart_get_point_cnt(chart) : ser->start_point;
|
|
for (uint16_t j = 0; j < ctx; ++j)
|
|
series.points << ser->points[j];
|
|
m_widget->m_series << series;
|
|
m_widget->m_seriesList->addItem(QString("Series %1").arg(i));
|
|
}
|
|
}
|
|
|
|
void LVGLPropertySeries::updateWidget(LVGLObject *obj)
|
|
{
|
|
lv_obj_t *chart = obj->obj();
|
|
Q_ASSERT(lv_debug_check_obj_type(chart, "lv_chart"));
|
|
|
|
lv_chart_ext_t *ext = reinterpret_cast<lv_chart_ext_t*>(lv_obj_get_ext_attr(chart));
|
|
|
|
int maxPoints = 0;
|
|
for (const auto &s:m_widget->m_series)
|
|
maxPoints = std::max(maxPoints, s.points.size());
|
|
|
|
// clear the chart series (maybe lvgl should add a function for this)
|
|
lv_chart_series_t *ser;
|
|
for (ser = reinterpret_cast<lv_chart_series_t*>(lv_ll_get_tail(&ext->series_ll));
|
|
ser != nullptr;
|
|
ser = reinterpret_cast<lv_chart_series_t*>(lv_ll_get_prev(&ext->series_ll, ser)))
|
|
{
|
|
lv_mem_free(ser->points);
|
|
lv_mem_free(ser);
|
|
}
|
|
lv_ll_clear(&ext->series_ll);
|
|
|
|
// add new charts
|
|
lv_chart_set_point_count(chart, static_cast<uint16_t>(maxPoints));
|
|
for (const auto &s:m_widget->m_series) {
|
|
lv_chart_series_t *ser = lv_chart_add_series(chart, lvgl.fromColor(s.color));
|
|
for (int i = 0; i < s.points.size(); ++i)
|
|
lv_chart_set_next(chart, ser, s.points[i]);
|
|
}
|
|
}
|
|
|
|
QStringList LVGLPropertySeries::function(LVGLObject *obj) const
|
|
{
|
|
QStringList ret;
|
|
|
|
lv_obj_t *chart = obj->obj();
|
|
Q_ASSERT(lv_debug_check_obj_type(chart, "lv_chart"));
|
|
|
|
lv_chart_ext_t *ext = reinterpret_cast<lv_chart_ext_t*>(lv_obj_get_ext_attr(chart));
|
|
|
|
lv_chart_series_t *ser;
|
|
size_t i = 1;
|
|
for (ser = reinterpret_cast<lv_chart_series_t*>(lv_ll_get_tail(&ext->series_ll));
|
|
ser != nullptr;
|
|
ser = reinterpret_cast<lv_chart_series_t*>(lv_ll_get_prev(&ext->series_ll, ser)), ++i)
|
|
{
|
|
const QString codeSerName = QString("ser_%1_%2").arg(obj->codeName()).arg(i);
|
|
const QString color = QVariant(lvgl.toColor(ser->color)).toString().replace("#", "0x");
|
|
ret << QString("lv_chart_series_t * %1 = lv_chart_add_series(%2, lv_color_hex(%3));").arg(codeSerName).arg(obj->codeName()).arg(color);
|
|
const uint16_t ctx = ser->start_point == 0 ? lv_chart_get_point_cnt(chart) : ser->start_point;
|
|
for (uint16_t j = 0; j < ctx; ++j)
|
|
ret << QString("lv_chart_set_next(%1, %2, %3);").arg(obj->codeName()).arg(codeSerName).arg(ser->points[j]);
|
|
ret << "";
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
QJsonValue LVGLPropertySeries::toJson(LVGLObject *obj) const
|
|
{
|
|
QJsonArray ret;
|
|
|
|
lv_obj_t *chart = obj->obj();
|
|
Q_ASSERT(lv_debug_check_obj_type(chart, "lv_chart"));
|
|
|
|
lv_chart_ext_t *ext = reinterpret_cast<lv_chart_ext_t*>(lv_obj_get_ext_attr(chart));
|
|
|
|
lv_chart_series_t *ser;
|
|
for (ser = reinterpret_cast<lv_chart_series_t*>(lv_ll_get_tail(&ext->series_ll));
|
|
ser != nullptr;
|
|
ser = reinterpret_cast<lv_chart_series_t*>(lv_ll_get_prev(&ext->series_ll, ser)))
|
|
{
|
|
QJsonArray values;
|
|
const uint16_t ctx = ser->start_point == 0 ? lv_chart_get_point_cnt(chart) : ser->start_point;
|
|
for (uint16_t j = 0; j < ctx; ++j)
|
|
values.append(ser->points[j]);
|
|
QJsonObject series({{"color", lvgl.colorToJson(ser->color)},
|
|
{"values", values}});
|
|
ret.append(series);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void LVGLPropertySeries::setValue(LVGLObject *obj, QVariant value)
|
|
{
|
|
lv_obj_t *chart = obj->obj();
|
|
Q_ASSERT(lv_debug_check_obj_type(chart, "lv_chart"));
|
|
|
|
if (value.type() == QVariant::List) {
|
|
QVariantList series = value.toList();
|
|
QVector<LVGLChartSeries> seriesList;
|
|
int maxPoints = 0;
|
|
for (const QVariant &s:series) {
|
|
QVariantMap map = s.toMap();
|
|
if (!map.contains("color") || !map.contains("values"))
|
|
continue;
|
|
LVGLChartSeries item;
|
|
item.ser = lv_chart_add_series(chart, lvgl.fromColor(map["color"]));
|
|
for (const QVariant &v:map["values"].toList()) {
|
|
item.points << static_cast<lv_coord_t>(v.toInt());
|
|
|
|
//lv_chart_set_next(chart, ser, static_cast<lv_coord_t>(v.toInt()));
|
|
}
|
|
maxPoints = std::max(maxPoints, item.points.size());
|
|
seriesList << item;
|
|
}
|
|
|
|
lv_chart_set_point_count(chart, static_cast<uint16_t>(maxPoints));
|
|
for (const auto &s:seriesList) {
|
|
for (int i = 0; i < s.points.size(); ++i)
|
|
lv_chart_set_next(chart, s.ser, s.points[i]);
|
|
}
|
|
}
|
|
}
|