From 0854a6ba7e956f32c94a08419e47ebe2eb986446 Mon Sep 17 00:00:00 2001 From: Sander Speetjens Date: Wed, 16 Apr 2025 19:09:16 +0200 Subject: [PATCH] UI Add spinboxes --- UI/ui.hpp | 3 + UI/ui_double_spinbox.cpp | 55 ++++++++++++++ UI/ui_double_spinbox.hpp | 31 ++++++++ UI/ui_hex_spinbox.cpp | 54 ++++++++++++++ UI/ui_hex_spinbox.hpp | 31 ++++++++ client/simulator_base.cpp | 129 +++++++++++++++++++++++++++++++++ client/simulator_base.hpp | 6 ++ client/simulators/test.cpp | 3 + client/simulators/test.ui | 104 ++++++++++++++------------ server/simulators/test_sim.cpp | 9 ++- server/simulators/test_sim.hpp | 3 + 11 files changed, 382 insertions(+), 46 deletions(-) create mode 100644 UI/ui_double_spinbox.cpp create mode 100644 UI/ui_double_spinbox.hpp create mode 100644 UI/ui_hex_spinbox.cpp create mode 100644 UI/ui_hex_spinbox.hpp diff --git a/UI/ui.hpp b/UI/ui.hpp index cee972a..bd8bab1 100644 --- a/UI/ui.hpp +++ b/UI/ui.hpp @@ -3,11 +3,14 @@ #include "ui_button.hpp" #include "ui_checkbox.hpp" #include "ui_combobox.hpp" +#include "ui_double_spinbox.hpp" #include "ui_dial.hpp" +#include "ui_hex_spinbox.hpp" #include "ui_label.hpp" #include "ui_led.hpp" #include "ui_plot.hpp" #include "ui_slider.hpp" +#include "ui_spinbox.hpp" #include "ui_table.hpp" #include "ui_textbox.hpp" #include "ui_thermo.hpp" diff --git a/UI/ui_double_spinbox.cpp b/UI/ui_double_spinbox.cpp new file mode 100644 index 0000000..a9f1257 --- /dev/null +++ b/UI/ui_double_spinbox.cpp @@ -0,0 +1,55 @@ +#include "ui_double_spinbox.hpp" + +UI_double_spinbox::UI_double_spinbox(QObject* parent) : UI_item(UI_DOUBLE_SPINBOX_TYPE, parent) +{ +} + +UI_double_spinbox::UI_double_spinbox(double min, double max, double value, QObject* parent) : UI_item(UI_DOUBLE_SPINBOX_TYPE, parent) +{ + m_min = min; + m_max = max; + m_value = value; +} + +void UI_double_spinbox::set_value(double value) +{ + if (value < m_min || value > m_max) + return; + if (value == m_value) + return; + + this->m_value = value; + emit ui_changed(); + emit changed(m_value); +} +double UI_double_spinbox::value() const +{ + return m_value; +} + +double UI_double_spinbox::min() const +{ + return m_min; +} +double UI_double_spinbox::max() const +{ + return m_max; +} + +void UI_double_spinbox::from_json(const json &j) +{ + UI_item::from_json(j); + + this->m_min = j.at("min"); + this->m_max = j.at("max"); + this->m_value = j.at("value"); +} + +json UI_double_spinbox::to_json(size_t id) const +{ + json j = UI_item::to_json(id); + j["min"] = this->m_min; + j["max"] = this->m_max; + j["value"] = this->m_value; + return j; +} diff --git a/UI/ui_double_spinbox.hpp b/UI/ui_double_spinbox.hpp new file mode 100644 index 0000000..00ac59b --- /dev/null +++ b/UI/ui_double_spinbox.hpp @@ -0,0 +1,31 @@ +#ifndef UI_DOUBLE_SPINBOX_H +#define UI_DOUBLE_SPINBOX_H + +#include "ui_item.hpp" + +#define UI_DOUBLE_SPINBOX_TYPE std::string("ui_double_spinbox") + +class UI_double_spinbox : public UI_item { + Q_OBJECT + public: + explicit UI_double_spinbox(QObject* parent = nullptr); + UI_double_spinbox(double min, double max, double value, QObject* parent = nullptr); + + void set_value(double value) override; + double value() const; + + double min() const; + double max() const; + + void from_json(const json &j) override; + json to_json(size_t id) const override; + signals: + void changed(double value); + + private: + double m_min; + double m_max; + double m_value; +}; + +#endif // UI_DOUBLE_SPINBOX_H diff --git a/UI/ui_hex_spinbox.cpp b/UI/ui_hex_spinbox.cpp new file mode 100644 index 0000000..dced440 --- /dev/null +++ b/UI/ui_hex_spinbox.cpp @@ -0,0 +1,54 @@ +#include "ui_hex_spinbox.hpp" + +UI_hex_spinbox::UI_hex_spinbox(QObject* parent) : UI_item(UI_HEX_SPINBOX_TYPE, parent) { +} + +UI_hex_spinbox::UI_hex_spinbox(double min, double max, double value, QObject* parent) : UI_item(UI_HEX_SPINBOX_TYPE, parent) +{ + m_min = min; + m_max = max; + m_value = value; +} + +void UI_hex_spinbox::set_value(double value) +{ + if (value < m_min || value > m_max) + return; + if (value == m_value) + return; + + this->m_value = value; + emit ui_changed(); + emit changed(m_value); +} +double UI_hex_spinbox::value() const +{ + return m_value; +} + +double UI_hex_spinbox::min() const +{ + return m_min; +} +double UI_hex_spinbox::max() const +{ + return m_max; +} + +void UI_hex_spinbox::from_json(const json &j) +{ + UI_item::from_json(j); + + this->m_min = j.at("min"); + this->m_max = j.at("max"); + this->m_value = j.at("value"); +} + +json UI_hex_spinbox::to_json(size_t id) const +{ + json j = UI_item::to_json(id); + j["min"] = this->m_min; + j["max"] = this->m_max; + j["value"] = this->m_value; + return j; +} diff --git a/UI/ui_hex_spinbox.hpp b/UI/ui_hex_spinbox.hpp new file mode 100644 index 0000000..d941860 --- /dev/null +++ b/UI/ui_hex_spinbox.hpp @@ -0,0 +1,31 @@ +#ifndef UI_HEX_SPINBOX_HPP +#define UI_HEX_SPINBOX_HPP + +#include "ui_item.hpp" + +#define UI_HEX_SPINBOX_TYPE std::string("ui_hex_spinbox") + +class UI_hex_spinbox : public UI_item { + Q_OBJECT + public: + explicit UI_hex_spinbox(QObject* parent = nullptr); + UI_hex_spinbox(double min, double max, double value, QObject* parent = nullptr); + + void set_value(double value) override; + double value() const; + + double min() const; + double max() const; + + void from_json(const json &j) override; + json to_json(size_t id) const override; + signals: + void changed(double value); + + private: + double m_min; + double m_max; + double m_value; +}; + +#endif // UI_HEX_SPINBOX_HPP diff --git a/client/simulator_base.cpp b/client/simulator_base.cpp index db87e90..67f09ef 100644 --- a/client/simulator_base.cpp +++ b/client/simulator_base.cpp @@ -147,6 +147,21 @@ void Simulator_base::UI_item_parser(json &input) process_ui_checkbox(ui_item, widget); continue; } + if (ui_item["type"] == "ui_spinbox") + { + process_ui_spinbox(ui_item, widget); + continue; + } + if (ui_item["type"] == "ui_double_spinbox") + { + process_ui_double_spinbox(ui_item, widget); + continue; + } + if (ui_item["type"] == "ui_hex_spinbox") + { + process_ui_hex_spinbox(ui_item, widget); + continue; + } if (ui_item["type"] == "ui_plot") { process_ui_plot(ui_item, widget); @@ -480,6 +495,87 @@ void Simulator_base::process_ui_led(json &ui_item, QWidget* widget) } } +void Simulator_base::process_ui_spinbox(json &ui_item, QWidget* widget) +{ + auto spinbox = qobject_cast(widget); + if (spinbox == nullptr) + { + SPDLOG_WARN("widget is not of type QSpinBox"); + return; + } + + double min = ui_item["min"]; + double max = ui_item["max"]; + double value = ui_item["value"]; + + if (min != spinbox->minimum()) + { + spinbox->setMinimum(min); + } + if (max != spinbox->maximum()) + { + spinbox->setMaximum(max); + } + if (value != spinbox->value()) + { + spinbox->setValue((int)value); + } +} + +void Simulator_base::process_ui_double_spinbox(json &ui_item, QWidget* widget) +{ + auto spinbox = qobject_cast(widget); + if (spinbox == nullptr) + { + SPDLOG_WARN("widget is not of type QDoubleSpinBox"); + return; + } + + double min = ui_item["min"]; + double max = ui_item["max"]; + double value = ui_item["value"]; + + if (min != spinbox->minimum()) + { + spinbox->setMinimum(min); + } + if (max != spinbox->maximum()) + { + spinbox->setMaximum(max); + } + if (value != spinbox->value()) + { + spinbox->setValue(value); + } +} + +void Simulator_base::process_ui_hex_spinbox(json &ui_item, QWidget* widget) +{ + auto spinbox = qobject_cast(widget); + if (spinbox == nullptr) + { + SPDLOG_WARN("widget is not of type HexSpinBox"); + return; + } + + double min = ui_item["min"]; + double max = ui_item["max"]; + double value = ui_item["value"]; + + if (min != spinbox->minimum()) + { + spinbox->setMinimum(min); + } + if (max != spinbox->maximum()) + { + spinbox->setMaximum(max); + } + if (value != spinbox->value()) + { + spinbox->setValue((int)value); + } +} + void Simulator_base::process_ui_plot(json &ui_item, QWidget* widget) { auto plot = qobject_cast(widget); @@ -614,6 +710,9 @@ void Simulator_base::setup_ui_item(QWidget *item, size_t index) setup_checkbox(item, index); setup_dial(item, index); setup_slider(item, index); + setup_spinbox(item, index); + setup_double_spinbox(item, index); + setup_hex_spinbox(item, index); setup_qwtplot(item, index); setup_can_ui(item, index); } @@ -667,6 +766,36 @@ void Simulator_base::setup_slider(QWidget *item, size_t index) [=, this] { m_web_socket->send_event(Web_socket_wrapper::Event::value_changed, index, slider->value()); }); } +void Simulator_base::setup_spinbox(QWidget *item, size_t index) +{ + QSpinBox *spinbox = qobject_cast(item); + if (spinbox == nullptr) + return; + + connect(spinbox, &QSpinBox::valueChanged, this, + [=, this](int value) { m_web_socket->send_event(Web_socket_wrapper::Event::value_changed, index, (double)value); }); +} + +void Simulator_base::setup_double_spinbox(QWidget *item, size_t index) +{ + QDoubleSpinBox *spinbox = qobject_cast(item); + if (spinbox == nullptr) + return; + + connect(spinbox, &QDoubleSpinBox::valueChanged, this, + [=, this](double value) { m_web_socket->send_event(Web_socket_wrapper::Event::value_changed, index, value); }); +} + +void Simulator_base::setup_hex_spinbox(QWidget *item, size_t index) +{ + HexSpinBox *spinbox = qobject_cast(item); + if (spinbox == nullptr) + return; + + connect(spinbox, &HexSpinBox::valueChanged, this, + [=, this](int value) { m_web_socket->send_event(Web_socket_wrapper::Event::value_changed, index, (double)value); }); +} + void Simulator_base::setup_qwtplot(QWidget *item, size_t index) { auto *plot = qobject_cast(item); diff --git a/client/simulator_base.hpp b/client/simulator_base.hpp index b9acce4..efc2455 100644 --- a/client/simulator_base.hpp +++ b/client/simulator_base.hpp @@ -48,6 +48,9 @@ class Simulator_base : public QMainWindow virtual void process_ui_checkbox(json &ui_item, QWidget* widget); virtual void process_ui_button(json &ui_item, QWidget* widget); virtual void process_ui_led(json &ui_item, QWidget* widget); + virtual void process_ui_spinbox(json &ui_item, QWidget* widget); + virtual void process_ui_double_spinbox(json &ui_item, QWidget* widget); + virtual void process_ui_hex_spinbox(json &ui_item, QWidget* widget); virtual void process_ui_plot(json &ui_item, QWidget* widget); virtual void process_ui_table(json &ui_item, QWidget* widget); virtual void process_ui_can(json &ui_item, QWidget* widget); @@ -58,6 +61,9 @@ class Simulator_base : public QMainWindow void setup_checkbox(QWidget *item, size_t index); void setup_dial(QWidget *item, size_t index); void setup_slider(QWidget *item, size_t index); + void setup_spinbox(QWidget *item, size_t index); + void setup_double_spinbox(QWidget *item, size_t index); + void setup_hex_spinbox(QWidget *item, size_t index); void setup_qwtplot(QWidget *item, size_t index); void setup_can_ui(QWidget *item, size_t index); diff --git a/client/simulators/test.cpp b/client/simulators/test.cpp index 1e668c4..a53d5fc 100644 --- a/client/simulators/test.cpp +++ b/client/simulators/test.cpp @@ -18,6 +18,9 @@ Test_Sim::Test_Sim(Web_socket_wrapper *web_socket, QWidget *parent) PUSH_UI_ITEM(checkBox); PUSH_UI_ITEM(plot); PUSH_UI_ITEM(table); + PUSH_UI_ITEM(spinBox); + PUSH_UI_ITEM(doubleSpinBox); + PUSH_UI_ITEM(hexSpinBox); } Test_Sim::~Test_Sim() diff --git a/client/simulators/test.ui b/client/simulators/test.ui index 64dfdc4..dc6a137 100644 --- a/client/simulators/test.ui +++ b/client/simulators/test.ui @@ -15,24 +15,10 @@ - - + + - PushButton - - - - - - - PushButton - - - - - - - CheckBox + TextLabel @@ -63,26 +49,35 @@ - - + + + + + - TextLabel + PushButton - - - - - - 0 - - - - - - - + + + + PushButton + + + + + + + + + + QFrame::Shape::StyledPanel + + + QFrame::Shadow::Raised + + @@ -98,21 +93,35 @@ - - - - - - - QFrame::Shape::StyledPanel - - - QFrame::Shadow::Raised + + + + CheckBox - - + + + + + + + + + 0 + + + + + + + + + + + + + @@ -155,6 +164,11 @@
plot_wrapper.hpp
1 + + HexSpinBox + QSpinBox +
hex_spinbox.hpp
+
diff --git a/server/simulators/test_sim.cpp b/server/simulators/test_sim.cpp index 88bf99f..0175a83 100644 --- a/server/simulators/test_sim.cpp +++ b/server/simulators/test_sim.cpp @@ -7,7 +7,8 @@ Test_Sim::Test_Sim(CAN_Wrapper *can_wrapper, QSerialPort *serial, QObject *paren m_label("Label", Color::White, Color::Black), m_checkbox("Option 1", Color::Default, Color::Default), m_slider("Slider", Color::White, Color::Black, 0, 100, 0), m_dial("Dial", Color::White, Color::Black, 0, 100, 0), m_thermo("Thermo", "%", Color::White, Color::Black, 0, 100, 0), m_led("Led", Color::White, Color::Red), - m_table(4, 4, {"Row 1", "Row 2", "Row 3", "Row 4"}, {"Column 1", "Column 2", "Column 3", "Column 4"}) + m_table(4, 4, {"Row 1", "Row 2", "Row 3", "Row 4"}, {"Column 1", "Column 2", "Column 3", "Column 4"}), + m_spinbox(0, 255, 0), m_double_spinbox(0, 255, 0), m_hex_spinbox(0, 255, 0) { m_thermo.set_start_color(Color::Red); m_thermo.set_end_color(Color::Red); @@ -26,6 +27,9 @@ Test_Sim::Test_Sim(CAN_Wrapper *can_wrapper, QSerialPort *serial, QObject *paren PUSH_UI_ITEM(m_checkbox); PUSH_UI_ITEM(m_plot); PUSH_UI_ITEM(m_table); + PUSH_UI_ITEM(m_spinbox); + PUSH_UI_ITEM(m_double_spinbox); + PUSH_UI_ITEM(m_hex_spinbox); for (size_t i = 0; i < m_table.capacity(); i++) { @@ -76,6 +80,9 @@ void Test_Sim::slider_changed(UI_slider *id, double value) m_dial.set_value(value); m_thermo.set_value(value); m_plot.add_value(value); + m_spinbox.set_value(value); + m_double_spinbox.set_value(value); + m_hex_spinbox.set_value(value); return; } } diff --git a/server/simulators/test_sim.hpp b/server/simulators/test_sim.hpp index e8c46c3..d032af4 100644 --- a/server/simulators/test_sim.hpp +++ b/server/simulators/test_sim.hpp @@ -24,4 +24,7 @@ class Test_Sim : public Simulator_base UI_led m_led; UI_plot m_plot; UI_table m_table; + UI_spinbox m_spinbox; + UI_double_spinbox m_double_spinbox; + UI_hex_spinbox m_hex_spinbox; };