Compare commits

..
4 Commits
Author SHA1 Message Date
sani7 67d7e959b1 Client 2026-09-30 12:33:21 +02:00
sani7 08fd5407c3 server
update websocket
updated to use protobuf
not quite finished with the Websocket message parser
2026-09-30 12:33:20 +02:00
sani7 022422b63c Update UI 2026-09-30 12:33:20 +02:00
sani7 4618c500c9 protobuf messages 2026-09-30 12:33:15 +02:00
67 changed files with 1572 additions and 2367 deletions
+2
View File
@@ -28,6 +28,8 @@ add_subdirectory(client)
# contains an "external" library we will link to
add_subdirectory(external)
add_subdirectory(protobuf)
# defines the executable
if(NOT EMSCRIPTEN)
add_subdirectory(server)
+2 -11
View File
@@ -1,5 +1,5 @@
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
if(NOT EMSCRIPTEN)
add_library(UI STATIC)
find_package(Qt6 REQUIRED COMPONENTS Core SerialBus)
@@ -33,17 +33,8 @@ target_include_directories(UI
target_link_libraries(UI
PUBLIC
Color
nlohmann_json::nlohmann_json
magic_enum::magic_enum
Qt::Core
Qt::SerialBus
UI_enum
)
endif()
add_library(UI_enum INTERFACE)
target_include_directories(UI_enum
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/enum
proto-ui
)
-25
View File
@@ -1,25 +0,0 @@
#pragma once
enum class UI_enum
{
ui_button,
ui_can,
ui_checkbox,
ui_combobox,
ui_dial,
ui_double_spinbox,
ui_hex_spinbox,
ui_label,
ui_led,
ui_plot,
ui_slider,
ui_spinbox,
ui_stacked_widget,
ui_status_bar,
ui_tab_widget,
ui_table,
ui_textbox,
ui_thermo,
end,
begin = 0
};
+32 -9
View File
@@ -1,24 +1,47 @@
#include "ui_button.hpp"
#include "ui_enum.hpp"
UI_button::UI_button(std::string text, Color fg_color, Color bg_color, QObject *parent)
: UI_item(UI_enum::ui_button, text, fg_color, bg_color, parent)
UI_button::UI_button(QString text, Color fg_color, Color bg_color, QObject *parent)
: UI_item(UI_typeGadget::UI_type::ui_button, parent)
{
m_ui_item.setLabel(UI_label_m());
m_ui_item.label().setText(text);
m_ui_item.label().mutColor().setFgColor(fg_color.color());
m_ui_item.label().mutColor().setBgColor(bg_color.color());
}
UI_button::UI_button(QObject *parent) : UI_item(UI_enum::ui_button, parent)
UI_button::UI_button(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_button, parent)
{
m_ui_item.setLabel(UI_label_m());
}
void UI_button::from_json(const json &j)
void UI_button::set_text(QString text)
{
UI_item::from_json(j);
m_ui_item.label().setText(text);
}
json UI_button::to_json(size_t id) const
QString UI_button::text() const
{
json j = UI_item::to_json(id);
return j;
return m_ui_item.label().text();
}
void UI_button::set_fg_color(Color color)
{
m_ui_item.label().mutColor().setFgColor(color.color());
}
Color UI_button::fg_color() const
{
return Color(m_ui_item.label().color().fgColor());
}
void UI_button::set_bg_color(Color color)
{
m_ui_item.label().mutColor().setBgColor(color.color());
}
Color UI_button::bg_color() const
{
return Color(m_ui_item.label().color().bgColor());
}
void UI_button::click()
+13 -10
View File
@@ -17,7 +17,7 @@ class UI_button : public UI_item
* @param bg_color The background color of the button
* @param parent The parent QObject
*/
UI_button(std::string text, Color fg_color, Color bg_color, QObject *parent = nullptr);
UI_button(QString text, Color fg_color, Color bg_color, QObject *parent = nullptr);
/**
* @brief Construct a UI button object
*
@@ -26,18 +26,21 @@ class UI_button : public UI_item
UI_button(QObject *parent = nullptr);
/**
* @brief Deserialize the button from JSON
*
* @param j The JSON object
* @brief set_text
* @param text The text field of the button
*/
void from_json(const json &j) override;
void set_text(QString text) override;
/**
* @brief Serialize the button to JSON
*
* @param id The id of the button
* @return json The JSON representation of the button
* @brief text
* @return The text field of the button
*/
json to_json(size_t id) const override;
QString text() const;
void set_fg_color(Color fg_color);
Color fg_color() const;
void set_bg_color(Color bg_color);
Color bg_color() const;
/**
* @brief Handle a click event on the button
+23 -71
View File
@@ -1,53 +1,49 @@
#include "ui_can.hpp"
template <class T> T ByteArrayToStdArray(const QByteArray &byteArray)
{
T stdArray;
for (unsigned int i = 0; i < stdArray.size() && i < (unsigned int)byteArray.size(); i++)
{
stdArray[i] = (unsigned char)byteArray.at(i);
}
return stdArray;
}
UI_can::UI_can(Color fg_color, Color bg_color, QObject *parent)
: UI_item(UI_enum::ui_can, "", fg_color, bg_color, parent)
: UI_item(UI_typeGadget::UI_type::ui_can, parent)
{
setup_item(false, true, true);
m_ui_item.can().mutColor().setFgColor(fg_color.color());
m_ui_item.can().mutColor().setBgColor(bg_color.color());
}
UI_can::UI_can(QObject *parent) : UI_item(UI_enum::ui_can, parent)
UI_can::UI_can(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_can, parent)
{
setup_item(false, true, true);
}
void UI_can::add_send_message(QCanBusFrame msg)
{
CanFrame frame(msg.frameId(), (uint8_t)msg.payload().size(),
ByteArrayToStdArray<std::array<uint8_t, 8>>(msg.payload()));
m_can_send_messages.push_back(frame);
CAN_Frame_m frame;(msg.frameId(), msg.payload().size(), msg.payload());
frame.setSid(msg.frameId());
frame.setDlc(msg.payload().size());
frame.setPayload(msg.payload());
auto send_frames = m_ui_item.can().sendFrames();
send_frames.append(frame);
m_ui_item.can().setSendFrames(send_frames);
emit ui_changed();
}
void UI_can::add_received_message(QCanBusFrame msg)
{
CanFrame frame(msg.frameId(), (uint8_t)msg.payload().size(),
ByteArrayToStdArray<std::array<uint8_t, 8>>(msg.payload()));
m_can_received_messages.push_back(frame);
CAN_Frame_m frame;(msg.frameId(), msg.payload().size(), msg.payload());
frame.setSid(msg.frameId());
frame.setDlc(msg.payload().size());
frame.setPayload(msg.payload());
auto recv_frames = m_ui_item.can().recvFrames();
recv_frames.append(frame);
m_ui_item.can().setRecvFrames(recv_frames);
emit ui_changed();
}
void UI_can::clear_send_buffer()
{
m_can_send_messages.clear();
m_ui_item.can().setSendFrames(QList<CAN_Frame_m>());
emit ui_changed();
}
void UI_can::clear_receive_buffer()
{
m_can_received_messages.clear();
m_ui_item.can().setSendFrames(QList<CAN_Frame_m>());
emit ui_changed();
}
@@ -57,56 +53,12 @@ void UI_can::clear()
clear_receive_buffer();
}
void UI_can::from_json(const json &j)
{
UI_item::from_json(j);
m_can_send_messages.clear();
m_can_received_messages.clear();
for (const auto &msg : j.at("send_msgs"))
{
CanFrame can_msg(msg.at("id"), msg.at("dlc"), msg.at("payload"));
m_can_send_messages.push_back(can_msg);
}
for (const auto &msg : j.at("rcvd_msgs"))
{
CanFrame can_msg(msg.at("id"), msg.at("dlc"), msg.at("payload"));
m_can_received_messages.push_back(can_msg);
}
}
json UI_can::to_json(size_t id) const
{
json j = UI_item::to_json(id);
json can_send_messages = json::array();
json can_received_messages = json::array();
for (const auto &msg : m_can_send_messages)
{
json can_msg;
can_msg["id"] = (uint32_t)msg.m_SID;
can_msg["dlc"] = msg.m_DLC;
can_msg["payload"] = msg.m_payload;
can_send_messages.push_back(can_msg);
}
j["send_msgs"] = can_send_messages;
for (const auto &msg : m_can_received_messages)
{
json can_msg;
can_msg["id"] = (uint32_t)msg.m_SID;
can_msg["dlc"] = msg.m_DLC;
can_msg["payload"] = msg.m_payload;
can_received_messages.push_back(can_msg);
}
j["rcvd_msgs"] = can_received_messages;
return j;
}
void UI_can::can_send(uint32_t id, uint8_t dlc, std::array<uint8_t, 8> payload)
void UI_can::can_send(uint32_t id, uint64_t dlc, QByteArray payload)
{
QCanBusFrame frame;
Q_UNUSED(dlc);
frame.setFrameId(id);
frame.setPayload(QByteArray::fromRawData((const char *)(payload.data()), dlc));
frame.setPayload(payload);
emit send(frame);
}
+1 -19
View File
@@ -83,20 +83,6 @@ class UI_can : public UI_item
*/
void clear_receive_buffer();
/**
* @brief Deserialize the CAN item from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the CAN item to JSON
*
* @param id The id of the CAN item
* @return json The JSON representation of the CAN item
*/
json to_json(size_t id) const override;
/**
* @brief Handle a CAN send event
*
@@ -104,7 +90,7 @@ class UI_can : public UI_item
* @param dlc The data length code
* @param payload The data payload
*/
void can_send(uint32_t id, uint8_t dlc, std::array<uint8_t, 8> payload) override;
void can_send(uint32_t id, uint64_t dlc, QByteArray payload) override;
/**
* @brief Clear the CAN item
*
@@ -116,8 +102,4 @@ class UI_can : public UI_item
* @param msg The CAN message sent
*/
void send(QCanBusFrame msg);
private:
std::vector<CanFrame> m_can_send_messages;
std::vector<CanFrame> m_can_received_messages;
};
+44 -25
View File
@@ -1,46 +1,65 @@
#include "ui_checkbox.hpp"
UI_checkbox::UI_checkbox(QObject *parent) : UI_item(UI_enum::ui_checkbox, parent), m_checked()
UI_checkbox::UI_checkbox(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_checkbox, parent)
{
m_ui_item.setCheckbox(UI_checkbox_m());
}
UI_checkbox::UI_checkbox(std::string text, Color fg_color, Color bg_color, QObject *parent)
: UI_item(UI_enum::ui_checkbox, text, fg_color, bg_color, parent), m_checked(false)
UI_checkbox::UI_checkbox(QString text, Color fg_color, Color bg_color, QObject *parent)
: UI_item(UI_typeGadget::UI_type::ui_checkbox, parent)
{
m_ui_item.setCheckbox(UI_checkbox_m());
m_ui_item.checkbox().setText(text);
m_ui_item.checkbox().setChecked(false);
m_ui_item.label().mutColor().setFgColor(fg_color.color());
m_ui_item.label().mutColor().setBgColor(bg_color.color());
}
void UI_checkbox::set_text(QString text)
{
m_ui_item.label().setText(text);
}
QString UI_checkbox::text() const
{
return m_ui_item.label().text();
}
void UI_checkbox::set_fg_color(Color color)
{
m_ui_item.label().mutColor().setFgColor(color.color());
}
Color UI_checkbox::fg_color() const
{
return Color(m_ui_item.label().color().fgColor());
}
void UI_checkbox::set_bg_color(Color color)
{
m_ui_item.label().mutColor().setBgColor(color.color());
}
Color UI_checkbox::bg_color() const
{
return Color(m_ui_item.label().color().bgColor());
}
void UI_checkbox::click()
{
m_checked = !m_checked;
m_ui_item.checkbox().setChecked(!m_ui_item.checkbox().checked());
emit ui_changed();
emit changed(m_checked);
emit changed(m_ui_item.checkbox().checked());
}
void UI_checkbox::set_state(bool state)
{
m_checked = state;
m_ui_item.checkbox().setChecked(state);
emit ui_changed();
emit changed(m_checked);
emit changed(m_ui_item.checkbox().checked());
}
bool UI_checkbox::state() const
{
return m_checked;
}
void UI_checkbox::from_json(const json &j)
{
UI_item::from_json(j);
if (j.contains("checked"))
{
m_checked = j["checked"];
}
}
json UI_checkbox::to_json(size_t id) const
{
json j = UI_item::to_json(id);
j["checked"] = m_checked;
return j;
return m_ui_item.checkbox().checked();
}
+18 -18
View File
@@ -23,7 +23,24 @@ class UI_checkbox : public UI_item
* @param bg_color The background color
* @param parent The parent QObject
*/
UI_checkbox(std::string text, Color fg_color, Color bg_color, QObject *parent = nullptr);
UI_checkbox(QString text, Color fg_color, Color bg_color, QObject *parent = nullptr);
/**
* @brief set_text
* @param text The text field of the button
*/
void set_text(QString text) override;
/**
* @brief text
* @return The text field of the button
*/
QString text() const;
void set_fg_color(Color fg_color);
Color fg_color() const;
void set_bg_color(Color bg_color);
Color bg_color() const;
/**
* @brief Handle a click event on the checkbox
@@ -44,20 +61,6 @@ class UI_checkbox : public UI_item
*/
bool state() const;
/**
* @brief Deserialize the checkbox from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the checkbox to JSON
*
* @param id The id of the checkbox
* @return json The JSON representation of the checkbox
*/
json to_json(size_t id) const override;
signals:
/**
* @brief Signal emitted when the checkbox state changes
@@ -65,7 +68,4 @@ class UI_checkbox : public UI_item
* @param checked The new state of the checkbox
*/
void changed(bool checked);
private:
bool m_checked;
};
+17 -37
View File
@@ -1,31 +1,33 @@
#include "ui_combobox.hpp"
UI_combobox::UI_combobox(QObject *parent) : UI_item(UI_enum::ui_combobox, parent), m_options()
UI_combobox::UI_combobox(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_combobox, parent)
{
setup_item(false, true, true);
m_ui_item.setCombobox(UI_combobox_m());
}
UI_combobox::UI_combobox(Color fg_color, Color bg_color, std::vector<std::string> options, size_t selected,
UI_combobox::UI_combobox(QList<QString> options, qsizetype selected,
QObject *parent)
: UI_item(UI_enum::ui_combobox, "", fg_color, bg_color, parent), m_options(options), m_selected(selected)
: UI_item(UI_typeGadget::UI_type::ui_combobox, parent)
{
setup_item(false, true, true);
m_ui_item.setCombobox(UI_combobox_m());
m_ui_item.combobox().setOptions(options);
m_ui_item.combobox().setSelected(selected);
}
void UI_combobox::set_selected(size_t selected)
void UI_combobox::set_selected(qsizetype selected)
{
if (selected == m_selected)
if (selected == m_ui_item.combobox().selected())
return;
m_selected = std::move(selected);
m_ui_item.combobox().setSelected(selected);
emit ui_changed();
emit changed(selected_text());
}
void UI_combobox::set_selected(std::string selected)
void UI_combobox::set_selected(QString selected)
{
for (size_t i = 0; i < m_options.size(); i++)
for (qsizetype i = 0; i < m_ui_item.combobox().options().size(); i++)
{
if (m_options[i] == selected)
if (m_ui_item.combobox().options().at(i) == selected)
{
set_selected(i);
return;
@@ -33,34 +35,12 @@ void UI_combobox::set_selected(std::string selected)
}
}
size_t UI_combobox::selected() const
qsizetype UI_combobox::selected() const
{
return m_selected;
return m_ui_item.combobox().selected();
}
std::string UI_combobox::selected_text() const &
QString UI_combobox::selected_text() const &
{
return m_options[m_selected];
}
void UI_combobox::from_json(const json &j)
{
UI_item::from_json(j);
if (j.contains("options"))
{
this->m_options.clear();
for (auto &option : j["options"])
{
this->m_options.push_back(option);
}
}
m_selected = j.at("selected");
}
json UI_combobox::to_json(size_t id) const
{
json j = UI_item::to_json(id);
j["options"] = this->m_options;
j["selected"] = m_selected;
return j;
return m_ui_item.combobox().options().at(m_ui_item.combobox().selected());
}
+11 -24
View File
@@ -24,56 +24,43 @@ class UI_combobox : public UI_item
* @param selected The initially selected option
* @param parent The parent QObject
*/
UI_combobox(Color fg_color, Color bg_color, std::vector<std::string> options, size_t selected = 0,
UI_combobox(QList<QString> options, qsizetype selected = 0,
QObject *parent = nullptr);
void set_fg_color(Color fg_color);
Color fg_color() const;
void set_bg_color(Color bg_color);
Color bg_color() const;
/**
* @brief Set the selected option by index
*
* @param selected The index of the option to select
*/
void set_selected(size_t selected) override;
void set_selected(qsizetype selected) override;
/**
* @brief Set the selected option by text
*
* @param selected The text of the option to select
*/
void set_selected(std::string selected);
void set_selected(QString selected);
/**
* @brief Get the index of the selected option
*
* @return size_t The index of the selected option
*/
size_t selected() const;
qsizetype selected() const;
/**
* @brief Get the text of the selected option
*
* @return std::string The text of the selected option
*/
std::string selected_text() const &;
/**
* @brief Deserialize the combobox from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the combobox to JSON
*
* @param id The id of the combobox
* @return json The JSON representation of the combobox
*/
json to_json(size_t id) const override;
QString selected_text() const &;
signals:
/**
* @brief Signal emitted when the selected option changes
*
* @param selected The text of the newly selected option
*/
void changed(std::string selected);
private:
std::vector<std::string> m_options;
size_t m_selected;
void changed(QString selected);
};
+19 -43
View File
@@ -1,78 +1,54 @@
#include "ui_dial.hpp"
UI_dial::UI_dial(std::string text, std::string unit, Color fg_color, Color bg_color, double min, double max,
UI_dial::UI_dial(QString text, QString unit, double min, double max,
double value, QObject *parent)
: UI_item(UI_enum::ui_dial, text, fg_color, bg_color, parent), m_min(min), m_max(max), m_value(value), m_unit(unit)
: UI_item(UI_typeGadget::UI_type::ui_dial, parent)
{
m_ui_item.setRange(UI_range_m());
m_ui_item.range().setText(text);
m_ui_item.range().setUnit(unit);
m_ui_item.range().setMin(min);
m_ui_item.range().setMax(max);
m_ui_item.range().setValue(value);
}
UI_dial::UI_dial(std::string text, std::string unit, double min, double max, double value, QObject *parent)
: UI_dial(text, unit, Color::Default, Color::Default, min, max, value, parent)
{
}
UI_dial::UI_dial(std::string text, Color fg_color, Color bg_color, double min, double max, double value,
UI_dial::UI_dial(QString text, double min, double max, double value,
QObject *parent)
: UI_dial(text, "", fg_color, bg_color, min, max, value, parent)
: UI_dial(text, "", min, max, value, parent)
{
}
UI_dial::UI_dial(std::string text, double min, double max, double value, QObject *parent)
: UI_dial(text, "", Color::Default, Color::Default, min, max, value, parent)
{
}
UI_dial::UI_dial(QObject *parent) : UI_item(UI_enum::ui_dial, parent)
UI_dial::UI_dial(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_dial, parent)
{
}
void UI_dial::set_value(double value)
{
if (value < m_min || value > m_max)
if (value < m_ui_item.range().min() || value > m_ui_item.range().max())
return;
if (value == m_value)
if (value == m_ui_item.range().value())
return;
this->m_value = value;
m_ui_item.range().setValue(value);
emit ui_changed();
}
double UI_dial::value() const
{
return m_value;
return m_ui_item.range().value();
}
double UI_dial::min() const
{
return m_min;
return m_ui_item.range().min();
}
double UI_dial::max() const
{
return m_max;
return m_ui_item.range().max();
}
std::string UI_dial::unit() const &
QString UI_dial::unit() const &
{
return m_unit;
}
void UI_dial::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");
this->m_unit = j.at("unit");
}
json UI_dial::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;
j["unit"] = this->m_unit;
return j;
return m_ui_item.range().unit();
}
+4 -51
View File
@@ -14,39 +14,12 @@ class UI_dial : public UI_item
*
* @param text The text to display
* @param unit The unit of the dial
* @param fg_color The foreground color
* @param bg_color The background color
* @param min The minimum value
* @param max The maximum value
* @param value The initial value
* @param parent The parent QObject
*/
UI_dial(std::string text, std::string unit, Color fg_color, Color bg_color, double min, double max, double value,
QObject *parent = nullptr);
/**
* @brief Construct a UI dial object
*
* @param text The text to display
* @param unit The unit of the dial
* @param min The minimum value
* @param max The maximum value
* @param value The initial value
* @param parent The parent QObject
*/
UI_dial(std::string text, std::string unit, double min, double max, double value, QObject *parent = nullptr);
/**
* @brief Construct a UI dial object
*
* @param text The text to display
* @param fg_color The foreground color
* @param bg_color The background color
* @param min The minimum value
* @param max The maximum value
* @param value The initial value
* @param parent The parent QObject
*/
UI_dial(std::string text, Color fg_color, Color bg_color, double min, double max, double value,
QObject *parent = nullptr);
UI_dial(QString text, QString unit, double min, double max, double value, QObject *parent = nullptr);
/**
* @brief Construct a UI dial object
*
@@ -56,7 +29,7 @@ class UI_dial : public UI_item
* @param value The initial value
* @param parent The parent QObject
*/
UI_dial(std::string text, double min, double max, double value, QObject *parent = nullptr);
UI_dial(QString text, double min, double max, double value, QObject *parent = nullptr);
/**
* @brief Construct a UI dial object
*
@@ -92,27 +65,7 @@ class UI_dial : public UI_item
/**
* @brief Get the unit of the dial
*
* @return std::string The unit of the dial
* @return QString The unit of the dial
*/
std::string unit() const &;
/**
* @brief Deserialize the dial from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the dial to JSON
*
* @param id The id of the dial
* @return json The JSON representation of the dial
*/
json to_json(size_t id) const override;
private:
double m_min;
double m_max;
double m_value;
std::string m_unit;
QString unit() const &;
};
+14 -32
View File
@@ -1,58 +1,40 @@
#include "ui_double_spinbox.hpp"
UI_double_spinbox::UI_double_spinbox(QObject *parent) : UI_item(UI_enum::ui_double_spinbox, parent)
UI_double_spinbox::UI_double_spinbox(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_double_spinbox, parent)
{
setup_item(false, false, false);
m_ui_item.setSpinbox(UI_spinbox_m());
}
UI_double_spinbox::UI_double_spinbox(double min, double max, double value, QObject *parent)
: UI_item(UI_enum::ui_double_spinbox, parent)
: UI_item(UI_typeGadget::UI_type::ui_double_spinbox, parent)
{
setup_item(false, false, false);
m_min = min;
m_max = max;
m_value = value;
m_ui_item.setSpinbox(UI_spinbox_m());
m_ui_item.spinbox().setMin(min);
m_ui_item.spinbox().setMax(max);
m_ui_item.spinbox().setValue(value);
}
void UI_double_spinbox::set_value(double value)
{
if (value < m_min || value > m_max)
if (value < m_ui_item.spinbox().min() || value > m_ui_item.spinbox().max())
return;
if (value == m_value)
if (value == m_ui_item.spinbox().value())
return;
this->m_value = value;
m_ui_item.spinbox().setValue(value);
emit ui_changed();
emit changed(m_value);
emit changed(m_ui_item.spinbox().value());
}
double UI_double_spinbox::value() const
{
return m_value;
return m_ui_item.spinbox().value();
}
double UI_double_spinbox::min() const
{
return m_min;
return m_ui_item.spinbox().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;
return m_ui_item.spinbox().max();
}
-19
View File
@@ -50,20 +50,6 @@ class UI_double_spinbox : public UI_item
* @return double The maximum value
*/
double max() const;
/**
* @brief Deserialize the double spinbox from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the double spinbox to JSON
*
* @param id The id of the double spinbox
* @return json The JSON representation of the double spinbox
*/
json to_json(size_t id) const override;
signals:
/**
* @brief Signal emitted when the double spinbox value changes
@@ -71,9 +57,4 @@ class UI_double_spinbox : public UI_item
* @param value The new value
*/
void changed(double value);
private:
double m_min;
double m_max;
double m_value;
};
+14 -32
View File
@@ -1,58 +1,40 @@
#include "ui_hex_spinbox.hpp"
UI_hex_spinbox::UI_hex_spinbox(QObject *parent) : UI_item(UI_enum::ui_hex_spinbox, parent)
UI_hex_spinbox::UI_hex_spinbox(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_hex_spinbox, parent)
{
setup_item(false, false, false);
m_ui_item.setSpinbox(UI_spinbox_m());
}
UI_hex_spinbox::UI_hex_spinbox(double min, double max, double value, QObject *parent)
: UI_item(UI_enum::ui_hex_spinbox, parent)
: UI_item(UI_typeGadget::UI_type::ui_hex_spinbox, parent)
{
setup_item(false, false, false);
m_min = min;
m_max = max;
m_value = value;
m_ui_item.setSpinbox(UI_spinbox_m());
m_ui_item.spinbox().setMin(min);
m_ui_item.spinbox().setMax(max);
m_ui_item.spinbox().setValue(value);
}
void UI_hex_spinbox::set_value(double value)
{
if (value < m_min || value > m_max)
if (value < m_ui_item.spinbox().min() || value > m_ui_item.spinbox().max())
return;
if (value == m_value)
if (value == m_ui_item.spinbox().value())
return;
this->m_value = value;
m_ui_item.spinbox().setValue(value);
emit ui_changed();
emit changed(m_value);
emit changed(m_ui_item.spinbox().value());
}
double UI_hex_spinbox::value() const
{
return m_value;
return m_ui_item.spinbox().value();
}
double UI_hex_spinbox::min() const
{
return m_min;
return m_ui_item.spinbox().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;
return m_ui_item.spinbox().max();
}
-19
View File
@@ -50,20 +50,6 @@ class UI_hex_spinbox : public UI_item
* @return double The maximum value
*/
double max() const;
/**
* @brief Deserialize the hex spinbox from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the hex spinbox to JSON
*
* @param id The id of the hex spinbox
* @return json The JSON representation of the hex spinbox
*/
json to_json(size_t id) const override;
signals:
/**
* @brief Signal emitted when the hex spinbox value changes
@@ -71,9 +57,4 @@ class UI_hex_spinbox : public UI_item
* @param value The new value
*/
void changed(double value);
private:
double m_min;
double m_max;
double m_value;
};
+34 -125
View File
@@ -1,172 +1,81 @@
#include "ui_item.hpp"
#include <magic_enum/magic_enum.hpp>
UI_item::UI_item(UI_enum type, std::string text, Color fg_color, Color bg_color, QObject *parent)
: QObject(parent), m_id((size_t)-1), m_type(type), m_text(text), m_fg_color(fg_color), m_bg_color(bg_color),
m_enabled(true), m_visible(true)
UI_item::UI_item(UI_typeGadget::UI_type type, QObject *parent)
: QObject(parent)
{
m_ui_item.setId_proto((size_t)-1);
m_ui_item.setType(type);
m_ui_item.setEnabled(true);
m_ui_item.setVisible(true);
}
UI_item::UI_item(UI_enum type, QObject *parent)
: QObject(parent), m_id((size_t)-1), m_type(type), m_text(""), m_fg_color(Color::Default),
m_bg_color(Color::Default), m_enabled(true), m_visible(true)
void UI_item::set_id(size_t id)
{
}
std::string_view UI_item::type() const &
{
return magic_enum::enum_name(m_type);
}
bool UI_item::is_type(json j)
{
if (!j.contains("type"))
{
return false;
}
return magic_enum::enum_cast<UI_enum>((std::string)j.at("type")).value_or(UI_enum::end) == m_type;
}
void UI_item::set_text(std::string text)
{
if (this->m_text != text)
{
this->m_text = std::move(text);
emit ui_changed();
}
}
void UI_item::append_text(std::string text)
{
m_text.append(text);
emit ui_changed();
}
std::string UI_item::text() const &
{
return m_text;
}
void UI_item::set_fg_color(Color fg_color)
{
if (this->m_fg_color != fg_color)
{
this->m_fg_color = std::move(fg_color);
emit ui_changed();
}
}
Color UI_item::fg_color() const &
{
return m_fg_color;
}
void UI_item::set_bg_color(Color bg_color)
{
if (this->m_bg_color != bg_color)
{
this->m_bg_color = std::move(bg_color);
emit ui_changed();
}
}
Color UI_item::bg_color() const &
{
return m_bg_color;
m_ui_item.setId_proto(id);
}
void UI_item::set_enabled(bool enabled)
{
if (this->m_enabled != enabled)
if (m_ui_item.enabled() != enabled)
{
this->m_enabled = std::move(enabled);
m_ui_item.setEnabled(enabled);
emit ui_changed();
}
}
bool UI_item::is_enabled() const
{
return m_enabled;
return m_ui_item.enabled();
}
void UI_item::set_visible(bool visible)
{
if (this->m_visible != visible)
if (m_ui_item.visible() != visible)
{
this->m_visible = std::move(visible);
m_ui_item.setVisible(visible);
emit ui_changed();
}
}
bool UI_item::is_visible() const
{
return m_visible;
return m_ui_item.visible();
}
void UI_item::from_json(const json &j)
UI_item_m UI_item::to_proto() const
{
if (!is_type(j))
return;
j.at("id").get_to(m_id);
if (j.contains("text"))
j.at("text").get_to(m_text);
std::string color;
if (j.contains("fg_color"))
{
j.at("fg_color").get_to(color);
m_fg_color = Color(color);
color.clear();
}
if (j.contains("bg_color"))
{
j.at("bg_color").get_to(color);
m_bg_color = Color(color);
}
j.at("enabled").get_to(m_enabled);
j.at("visible").get_to(m_visible);
return m_ui_item;
}
json UI_item::to_json(size_t id) const
void UI_item::from_proto(UI_item_m item)
{
json j;
j["id"] = id;
j["type"] = type();
if (m_text_enabled)
j["text"] = m_text;
if (m_fg_color_enabled)
j["fg_color"] = m_fg_color.to_hex();
if (m_bg_color_enabled)
j["bg_color"] = m_bg_color.to_hex();
j["enabled"] = m_enabled;
j["visible"] = m_visible;
return j;
m_ui_item = item;
}
void UI_item::click() {};
void UI_item::set_selected(size_t selected)
void UI_item::set_selected(qsizetype selected)
{
UNUSED(selected);
};
Q_UNUSED(selected);
}
void UI_item::set_text(QString text)
{
Q_UNUSED(text);
}
void UI_item::set_value(double value)
{
UNUSED(value);
};
Q_UNUSED(value);
}
void UI_item::can_send(uint32_t id, uint8_t dlc, std::array<uint8_t, 8> payload)
void UI_item::can_send(uint32_t id, uint64_t dlc, QByteArray payload)
{
UNUSED(id);
UNUSED(dlc);
UNUSED(payload);
};
Q_UNUSED(id);
Q_UNUSED(dlc);
Q_UNUSED(payload);
}
void UI_item::clear()
{
}
void UI_item::setup_item(bool text, bool fg_color, bool bg_color)
{
m_text_enabled = text;
m_fg_color_enabled = fg_color;
m_bg_color_enabled = bg_color;
}
+15 -147
View File
@@ -1,15 +1,13 @@
#pragma once
#include "color.hpp"
#include "ui_enum.hpp"
#include <magic_enum/magic_enum.hpp>
#include "m_ui_items.qpb.h"
#include <QProtobufSerializer>
#include <cstdint>
#include <nlohmann/json.hpp>
#include <string>
#include <QCanBusFrame>
#include <QObject>
using json = nlohmann::json;
#define UNUSED(x) (void)(x)
/**
* @brief Base class representing a UI item
@@ -25,77 +23,14 @@ class UI_item : public QObject
* @param type The type of the UI item
* @param parent The parent QObject
*/
explicit UI_item(UI_enum type, QObject *parent = nullptr);
/**
* @brief Construct a new UI item object
*
* @param type The type of the UI item
* @param text The text of the UI item
* @param fg_color The foreground color of the UI item
* @param bg_color The background color of the UI item
* @param parent The parent QObject
*/
explicit UI_item(UI_enum type, std::string text, Color fg_color, Color bg_color, QObject *parent = nullptr);
explicit UI_item(UI_typeGadget::UI_type type, QObject *parent = nullptr);
/**
* @brief Get the type of the UI item
* @brief set_id Function for setting ID, DO NOT USE THIS IN A SIM YOURSELF
*
* @return std::string The type of the UI item
* @param id
*/
std::string_view type() const &;
/**
* @brief Check if the JSON object is of the correct type
*
* @param j The JSON object
* @return true If the JSON object is of the correct type
* @return false If the JSON object is not of the correct type
*/
bool is_type(json j);
/**
* @brief Set the text of the UI item
*
* @param text The text to set
*/
virtual void set_text(std::string text);
/**
* @brief Append text to the UI item
*
* @param text The text to append
*/
void append_text(std::string text);
/**
* @brief Get the text of the UI item
*
* @return std::string The text of the UI item
*/
std::string text() const &;
/**
* @brief Set the foreground color of the UI item
*
* @param fg_color The foreground color to set
*/
void set_fg_color(Color fg_color);
/**
* @brief Get the foreground color of the UI item
*
* @return Color The foreground color of the UI item
*/
Color fg_color() const &;
/**
* @brief Set the background color of the UI item
*
* @param bg_color The background color to set
*/
void set_bg_color(Color bg_color);
/**
* @brief Get the background color of the UI item
*
* @return Color The background color of the UI item
*/
Color bg_color() const &;
void set_id(size_t id);
/**
* @brief Enable or disable the UI item
@@ -125,20 +60,8 @@ class UI_item : public QObject
*/
bool is_visible() const;
/**
* @brief Deserialize the UI item from JSON
*
* @param j The JSON object
*/
virtual void from_json(const json &j);
/**
* @brief Serialize the UI item to JSON
*
* @param id The id of the UI item
* @return json The JSON representation of the UI item
*/
virtual json to_json(size_t id) const;
UI_item_m to_proto() const;
void from_proto(UI_item_m item);
/**
* @brief Virtual method to handle click events
@@ -150,7 +73,10 @@ class UI_item : public QObject
*
* @param selected The index of the option to select
*/
virtual void set_selected(size_t selected);
virtual void set_selected(qsizetype selected);
virtual void set_text(QString text);
/**
* @brief Virtual method to set the value (for spinboxes)
*
@@ -164,7 +90,7 @@ class UI_item : public QObject
* @param dlc The data length code
* @param payload The payload data
*/
virtual void can_send(uint32_t id, uint8_t dlc, std::array<uint8_t, 8> payload);
virtual void can_send(uint32_t id, uint64_t dlc, QByteArray payload);
/**
* @brief Virtual method to clear the UI item
*
@@ -179,63 +105,5 @@ class UI_item : public QObject
void ui_changed();
protected:
/**
* @brief Setup the UI item properties
*
* @param text Enable text property
* @param fg_color Enable foreground color property
* @param bg_color Enable background color property
*/
void setup_item(bool text, bool fg_color, bool bg_color);
/**
* @brief The id of the UI item
*
*/
size_t m_id;
/**
* @brief The type of the UI item
*
*/
UI_enum m_type;
/**
* @brief The text of the UI item
*
*/
std::string m_text;
/**
* @brief Whether the text property is enabled
*
*/
bool m_text_enabled = true;
/**
* @brief The foreground color of the UI item
*
*/
Color m_fg_color;
/**
* @brief Whether the foreground color property is enabled
*
*/
bool m_fg_color_enabled = true;
/**
* @brief The background color of the UI item
*
*/
Color m_bg_color;
/**
* @brief Whether the background color property is enabled
*
*/
bool m_bg_color_enabled = true;
/**
* @brief Whether the UI item is enabled
*
*/
bool m_enabled;
/**
* @brief Whether the UI item is visible
*
*/
bool m_visible;
UI_item_m m_ui_item;
};
+39 -7
View File
@@ -1,20 +1,52 @@
#include "ui_label.hpp"
UI_label::UI_label(std::string text, Color fg_color, Color bg_color, QObject *parent)
: UI_item(UI_enum::ui_label, text, fg_color, bg_color, parent)
UI_label::UI_label(QString text, Color fg_color, Color bg_color, QObject *parent)
: UI_item(UI_typeGadget::UI_type::ui_label, parent)
{
m_ui_item.setLabel(UI_label_m());
m_ui_item.label().setText(text);
m_ui_item.label().mutColor().setFgColor(fg_color.color());
m_ui_item.label().mutColor().setBgColor(bg_color.color());
}
UI_label::UI_label(QObject *parent) : UI_item(UI_enum::ui_label, parent)
UI_label::UI_label(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_label, parent)
{
m_ui_item.setLabel(UI_label_m());
}
void UI_label::from_json(const json &j)
void UI_label::set_text(QString text)
{
UI_item::from_json(j);
m_ui_item.label().setText(text);
}
json UI_label::to_json(size_t id) const
void UI_label::append_text(QString text)
{
return UI_item::to_json(id);
QString prev = m_ui_item.label().text();
prev.append(text);
m_ui_item.label().setText(prev);
}
QString UI_label::text() const
{
return m_ui_item.label().text();
}
void UI_label::set_fg_color(Color color)
{
m_ui_item.label().mutColor().setFgColor(color.color());
}
Color UI_label::fg_color() const
{
return Color(m_ui_item.label().color().fgColor());
}
void UI_label::set_bg_color(Color color)
{
m_ui_item.label().mutColor().setBgColor(color.color());
}
Color UI_label::bg_color() const
{
return Color(m_ui_item.label().color().bgColor());
}
+19 -10
View File
@@ -18,7 +18,7 @@ class UI_label : public UI_item
* @param bg_color The background color
* @param parent The parent QObject
*/
UI_label(std::string text, Color fg_color, Color bg_color, QObject *parent = nullptr);
UI_label(QString text, Color fg_color, Color bg_color, QObject *parent = nullptr);
/**
* @brief Construct a UI label object
*
@@ -27,16 +27,25 @@ class UI_label : public UI_item
UI_label(QObject *parent = nullptr);
/**
* @brief Deserialize the label from JSON
*
* @param j The JSON object
* @brief set_text
* @param text The text field of the button
*/
void from_json(const json &j) override;
void set_text(QString text);
/**
* @brief Serialize the label to JSON
*
* @param id The id of the label
* @return json The JSON representation of the label
* @brief append_text Append
* @param text
*/
json to_json(size_t id) const override;
void append_text(QString text);
/**
* @brief text
* @return The text field of the button
*/
QString text() const;
void set_fg_color(Color fg_color);
Color fg_color() const;
void set_bg_color(Color bg_color);
Color bg_color() const;
};
+38 -14
View File
@@ -1,12 +1,47 @@
#include "ui_led.hpp"
UI_led::UI_led(QObject *parent) : UI_item(UI_enum::ui_led, "", Color::Default, Color::Default, parent)
UI_led::UI_led(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_led, parent)
{
m_ui_item.setLabel(UI_label_m());
}
UI_led::UI_led(std::string text, Color fg_color, Color bg_color, QObject *parent)
: UI_item(UI_enum::ui_led, text, fg_color, bg_color, parent)
UI_led::UI_led(QString text, Color fg_color, Color bg_color, QObject *parent)
: UI_item(UI_typeGadget::UI_type::ui_led, parent)
{
m_ui_item.setLabel(UI_label_m());
m_ui_item.label().setText(text);
m_ui_item.label().mutColor().setFgColor(fg_color.color());
m_ui_item.label().mutColor().setBgColor(bg_color.color());
}
void UI_led::set_text(QString text)
{
m_ui_item.label().setText(text);
}
QString UI_led::text() const
{
return m_ui_item.label().text();
}
void UI_led::set_fg_color(Color color)
{
m_ui_item.label().mutColor().setFgColor(color.color());
}
Color UI_led::fg_color() const
{
return Color(m_ui_item.label().color().fgColor());
}
void UI_led::set_bg_color(Color color)
{
m_ui_item.label().mutColor().setBgColor(color.color());
}
Color UI_led::bg_color() const
{
return Color(m_ui_item.label().color().bgColor());
}
bool UI_led::set_led(bool state, Color on, Color off)
@@ -14,14 +49,3 @@ bool UI_led::set_led(bool state, Color on, Color off)
set_bg_color(state ? on : off);
return state;
}
void UI_led::from_json(const json &j)
{
UI_item::from_json(j);
}
json UI_led::to_json(size_t id) const
{
json j = UI_item::to_json(id);
return j;
}
+18 -15
View File
@@ -24,7 +24,24 @@ class UI_led : public UI_item
* @param bg_color The background color
* @param parent The parent QObject
*/
UI_led(std::string text, Color fg_color, Color bg_color, QObject *parent = nullptr);
UI_led(QString text, Color fg_color, Color bg_color, QObject *parent = nullptr);
/**
* @brief set_text
* @param text The text field of the button
*/
void set_text(QString text) override;
/**
* @brief text
* @return The text field of the button
*/
QString text() const;
void set_fg_color(Color fg_color);
Color fg_color() const;
void set_bg_color(Color bg_color);
Color bg_color() const;
/**
* @brief Set the state of the LED
@@ -35,18 +52,4 @@ class UI_led : public UI_item
* @return state
*/
bool set_led(bool state, Color on, Color off);
/**
* @brief Deserialize the LED from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the LED to JSON
*
* @param id The id of the LED
* @return json The JSON representation of the LED
*/
json to_json(size_t id) const override;
};
+58 -41
View File
@@ -1,88 +1,105 @@
#include "ui_plot.hpp"
UI_plot::UI_plot(QObject *parent) : UI_item{UI_enum::ui_plot, parent}
UI_plot::UI_plot(QObject *parent) : UI_item{UI_typeGadget::UI_type::ui_plot, parent}
{
m_ui_item.setPlot(UI_plot_m());
}
UI_plot::UI_plot(std::string text, std::string x_label, std::string y_label, QObject *parent)
: UI_item(UI_enum::ui_plot, parent), m_x_label(x_label), m_y_label(y_label)
UI_plot::UI_plot(QString text, QString x_label, QString y_label, QObject *parent)
: UI_item(UI_typeGadget::UI_type::ui_plot, parent)
{
set_text(text);
m_ui_item.setPlot(UI_plot_m());
m_ui_item.plot().setText(text);
m_ui_item.plot().setXLabel(x_label);
m_ui_item.plot().setYLabel(y_label);
}
void UI_plot::set_x_label(std::string name)
void UI_plot::set_x_label(QString name)
{
m_x_label = std::move(name);
m_ui_item.plot().setXLabel(name);
emit ui_changed();
}
std::string UI_plot::x_label() const &
QString UI_plot::x_label() const &
{
return m_x_label;
return m_ui_item.plot().xLabel();
}
void UI_plot::set_y_label(std::string name)
void UI_plot::set_y_label(QString name)
{
m_y_label = std::move(name);
m_ui_item.plot().setYLabel(name);
emit ui_changed();
}
std::string UI_plot::y_label() const &
QString UI_plot::y_label() const &
{
return m_y_label;
return m_ui_item.plot().yLabel();
}
void UI_plot::set_fg_color(Color color)
{
m_ui_item.plot().mutColor().setFgColor(color.color());
emit ui_changed();
}
Color UI_plot::fg_color() const&
{
return Color(m_ui_item.plot().color().fgColor());
}
void UI_plot::set_bg_color(Color color)
{
m_ui_item.plot().mutColor().setBgColor(color.color());
emit ui_changed();
}
Color UI_plot::bg_color() const
{
return Color(m_ui_item.plot().color().bgColor());
}
void UI_plot::add_value(double y)
{
m_x_vals.push_back((double)m_x_vals.size());
m_y_vals.push_back(y);
auto x_vals = m_ui_item.plot().xVals();
auto y_vals = m_ui_item.plot().yVals();
x_vals.push_back((double)x_vals.size());
y_vals.push_back(y);
m_ui_item.plot().setXVals(x_vals);
m_ui_item.plot().setYVals(y_vals);
emit ui_changed();
}
void UI_plot::add_value(double x, double y)
{
m_x_vals.push_back(x);
m_y_vals.push_back(y);
auto x_vals = m_ui_item.plot().xVals();
auto y_vals = m_ui_item.plot().yVals();
x_vals.push_back(x);
y_vals.push_back(y);
m_ui_item.plot().setXVals(x_vals);
m_ui_item.plot().setYVals(y_vals);
emit ui_changed();
}
const std::vector<double> &UI_plot::x_vals() const &
const QList<double> &UI_plot::x_vals() const &
{
return m_x_vals;
return m_ui_item.plot().xVals();
}
const std::vector<double> &UI_plot::y_vals() const &
const QList<double> &UI_plot::y_vals() const &
{
return m_y_vals;
return m_ui_item.plot().yVals();
}
void UI_plot::clean_vals()
{
m_x_vals.clear();
m_y_vals.clear();
m_ui_item.plot().setXVals(QList<double>());
m_ui_item.plot().setYVals(QList<double>());
emit ui_changed();
}
void UI_plot::from_json(const json &j)
{
UI_item::from_json(j);
this->m_x_label = j.at("x_label");
this->m_y_label = j.at("y_label");
this->m_x_vals = (std::vector<double>)j.at("x_vals");
this->m_y_vals = (std::vector<double>)j.at("y_vals");
}
json UI_plot::to_json(size_t id) const
{
json j = UI_item::to_json(id);
j["x_label"] = m_x_label;
j["y_label"] = m_y_label;
j["x_vals"] = m_x_vals;
j["y_vals"] = m_y_vals;
return j;
}
+29 -29
View File
@@ -23,33 +23,53 @@ class UI_plot : public UI_item
* @param y_label The label for the y-axis
* @param parent The parent QObject
*/
UI_plot(std::string text, std::string x_label, std::string y_label, QObject *parent = nullptr);
UI_plot(QString text, QString x_label, QString y_label, QObject *parent = nullptr);
/**
* @brief Set the label for the x-axis
*
* @param name The name to set
*/
void set_x_label(std::string name);
void set_x_label(QString name);
/**
* @brief Get the label for the x-axis
*
* @return std::string The x-axis label
* @return QString The x-axis label
*/
std::string x_label() const &;
QString x_label() const &;
/**
* @brief Set the label for the y-axis
*
* @param name The name to set
*/
void set_y_label(std::string name);
void set_y_label(QString name);
/**
* @brief Get the label for the y-axis
*
* @return std::string The y-axis label
* @return QString The y-axis label
*/
std::string y_label() const &;
QString y_label() const &;
/**
* @brief set_fg_color Set the pen color
* @param color The color
*/
void set_fg_color(Color color);
/**
* @brief fg_color Get the pen color
* @return The color
*/
Color fg_color() const&;
/**
* @brief set_bg_color Set the background color
* @param color The color
*/
void set_bg_color(Color color);
/**
* @brief bg_color Get the background color
* @return The color
*/
Color bg_color() const;
/**
* @brief Add a value to the plot
@@ -70,37 +90,17 @@ class UI_plot : public UI_item
*
* @return a list of x values and a list of y values
*/
const std::vector<double> &x_vals() const &;
const QList<double> &x_vals() const &;
/**
* @brief Get the y values of the plot
* This is only for testing purposes
*
* @return a list of y values
*/
const std::vector<double> &y_vals() const &;
const QList<double> &y_vals() const &;
/**
* @brief Clear all values from the plot
*
*/
void clean_vals();
/**
* @brief Deserialize the plot from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the plot to JSON
*
* @param id The id of the plot
* @return json The JSON representation of the plot
*/
json to_json(size_t id) const override;
private:
std::vector<double> m_x_vals;
std::vector<double> m_y_vals;
std::string m_x_label;
std::string m_y_label;
};
+19 -43
View File
@@ -1,75 +1,51 @@
#include "ui_slider.hpp"
UI_slider::UI_slider(std::string text, std::string unit, Color fg_color, Color bg_color, double min, double max,
UI_slider::UI_slider(QString text, QString unit, double min, double max,
double value, QObject *parent)
: UI_item(UI_enum::ui_slider, text, fg_color, bg_color, parent), m_min(min), m_max(max), m_value(value),
m_unit(unit)
: UI_item(UI_typeGadget::UI_type::ui_slider, parent)
{
m_ui_item.setRange(UI_range_m());
m_ui_item.range().setText(text);
m_ui_item.range().setUnit(unit);
m_ui_item.range().setMax(max);
m_ui_item.range().setMin(min);
m_ui_item.range().setValue(value);
}
UI_slider::UI_slider(std::string text, std::string unit, double min, double max, double value, QObject *parent)
: UI_slider(text, unit, Color::Default, Color::Default, min, max, value, parent)
{
}
UI_slider::UI_slider(std::string text, Color fg_color, Color bg_color, double min, double max, double value,
UI_slider::UI_slider(QString text, double min, double max, double value,
QObject *parent)
: UI_slider(text, "", fg_color, bg_color, min, max, value, parent)
: UI_slider(text, "", min, max, value, parent)
{
}
UI_slider::UI_slider(std::string text, double min, double max, double value, QObject *parent)
: UI_slider(text, "", Color::Default, Color::Default, min, max, value, parent)
{
}
UI_slider::UI_slider(QObject *parent) : UI_item(UI_enum::ui_slider, parent)
UI_slider::UI_slider(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_slider, parent)
{
m_ui_item.setRange(UI_range_m());
}
void UI_slider::set_value(double value)
{
if (value < m_min || value > m_max)
if (value < m_ui_item.range().min() || value > m_ui_item.range().max())
return;
if (value == m_value)
if (value == m_ui_item.range().value())
return;
this->m_value = value;
m_ui_item.range().setValue(value);
emit ui_changed();
emit changed(m_value);
emit changed(m_ui_item.range().value());
}
double UI_slider::value() const
{
return m_value;
return m_ui_item.range().value();
}
double UI_slider::min() const
{
return m_min;
return m_ui_item.range().min();
}
double UI_slider::max() const
{
return m_max;
}
void UI_slider::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");
this->m_unit = j.at("unit");
}
json UI_slider::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;
j["unit"] = this->m_unit;
return j;
return m_ui_item.range().max();
}
+3 -45
View File
@@ -14,26 +14,13 @@ class UI_slider : public UI_item
*
* @param text The text to display
* @param unit The unit of the slider
* @param fg_color The foreground color
* @param bg_color The background color
* @param min The minimum value
* @param max The maximum value
* @param value The initial value
* @param parent The parent QObject
*/
UI_slider(std::string text, std::string unit, Color fg_color, Color bg_color, double min, double max, double value,
UI_slider(QString text, QString unit, double min, double max, double value,
QObject *parent = nullptr);
/**
* @brief Construct a UI slider object
*
* @param text The text to display
* @param unit The unit of the slider
* @param min The minimum value
* @param max The maximum value
* @param value The initial value
* @param parent The parent QObject
*/
UI_slider(std::string text, std::string unit, double min, double max, double value, QObject *parent = nullptr);
/**
* @brief Construct a UI slider object
*
@@ -45,18 +32,9 @@ class UI_slider : public UI_item
* @param value The initial value
* @param parent The parent QObject
*/
UI_slider(std::string text, Color fg_color, Color bg_color, double min, double max, double value,
UI_slider(QString text, double min, double max, double value,
QObject *parent = nullptr);
/**
* @brief Construct a UI slider object
*
* @param text The text to display
* @param min The minimum value
* @param max The maximum value
* @param value The initial value
* @param parent The parent QObject
*/
UI_slider(std::string text, double min, double max, double value, QObject *parent = nullptr);
/**
* @brief Construct a UI slider object
*
@@ -89,20 +67,6 @@ class UI_slider : public UI_item
* @return double The maximum value
*/
double max() const;
/**
* @brief Deserialize the slider from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the slider to JSON
*
* @param id The id of the slider
* @return json The JSON representation of the slider
*/
json to_json(size_t id) const override;
signals:
/**
* @brief Signal emitted when the slider value changes
@@ -110,10 +74,4 @@ class UI_slider : public UI_item
* @param value The new value of the slider
*/
void changed(double value);
private:
double m_min;
double m_max;
double m_value;
std::string m_unit;
};
+14 -32
View File
@@ -1,57 +1,39 @@
#include "ui_spinbox.hpp"
UI_spinbox::UI_spinbox(QObject *parent) : UI_item(UI_enum::ui_spinbox, parent)
UI_spinbox::UI_spinbox(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_spinbox, parent)
{
setup_item(false, false, false);
m_ui_item.setSpinbox(UI_spinbox_m());
}
UI_spinbox::UI_spinbox(double min, double max, double value, QObject *parent) : UI_item(UI_enum::ui_spinbox, parent)
UI_spinbox::UI_spinbox(double min, double max, double value, QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_spinbox, parent)
{
setup_item(false, false, false);
m_min = min;
m_max = max;
m_value = value;
m_ui_item.setSpinbox(UI_spinbox_m());
m_ui_item.spinbox().setMin(min);
m_ui_item.spinbox().setMax(max);
m_ui_item.spinbox().setValue(value);
}
void UI_spinbox::set_value(double value)
{
if (value < m_min || value > m_max)
if (value < m_ui_item.spinbox().min() || value > m_ui_item.spinbox().max())
return;
if (value == m_value)
if (value == m_ui_item.spinbox().value())
return;
this->m_value = value;
m_ui_item.spinbox().setValue(value);
emit ui_changed();
emit changed(m_value);
emit changed(m_ui_item.spinbox().value());
}
double UI_spinbox::value() const
{
return m_value;
return m_ui_item.spinbox().value();
}
double UI_spinbox::min() const
{
return m_min;
return m_ui_item.spinbox().min();
}
double UI_spinbox::max() const
{
return m_max;
}
void UI_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_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;
return m_ui_item.spinbox().max();
}
-19
View File
@@ -50,20 +50,6 @@ class UI_spinbox : public UI_item
* @return double The maximum value
*/
double max() const;
/**
* @brief Deserialize the spinbox from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the spinbox to JSON
*
* @param id The id of the spinbox
* @return json The JSON representation of the spinbox
*/
json to_json(size_t id) const override;
signals:
/**
* @brief Signal emitted when the spinbox value changes
@@ -71,9 +57,4 @@ class UI_spinbox : public UI_item
* @param value The new value of the spinbox
*/
void changed(double value);
private:
double m_min;
double m_max;
double m_value;
};
+14 -24
View File
@@ -1,44 +1,34 @@
#include "ui_stacked_widget.hpp"
UI_stacked_widget::UI_stacked_widget(QObject *parent) : UI_item(UI_enum::ui_stacked_widget, parent)
UI_stacked_widget::UI_stacked_widget(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_stacked_widget, parent)
{
m_ui_item.setStackedWidget(UI_stacked_widget_m());
}
UI_stacked_widget::UI_stacked_widget(size_t tab_count, size_t current_tab, QObject *parent)
: UI_item(UI_enum::ui_stacked_widget, parent), m_tab_count(tab_count), m_current_tab(current_tab)
UI_stacked_widget::UI_stacked_widget(qsizetype tab_count, qsizetype current_tab, QObject *parent)
: UI_item(UI_typeGadget::UI_type::ui_stacked_widget, parent)
{
m_ui_item.setStackedWidget(UI_stacked_widget_m());
m_ui_item.stackedWidget().setTabCount(tab_count);
m_ui_item.stackedWidget().setCurrentTab(current_tab);
}
void UI_stacked_widget::set_selected(size_t selected)
void UI_stacked_widget::set_selected(qsizetype selected)
{
if (selected >= m_tab_count)
if (selected >= m_ui_item.stackedWidget().tabCount())
return;
m_current_tab = selected;
m_ui_item.stackedWidget().setCurrentTab(selected);
emit ui_changed();
}
size_t UI_stacked_widget::selected() const
qsizetype UI_stacked_widget::selected() const
{
return m_current_tab;
return m_ui_item.stackedWidget().currentTab();
}
void UI_stacked_widget::advance_tab()
{
if (m_tab_count == 0)
if (m_ui_item.stackedWidget().tabCount() == 0)
return;
m_current_tab = (m_current_tab + 1) % m_tab_count;
m_ui_item.stackedWidget().setCurrentTab((m_ui_item.stackedWidget().currentTab() + 1) % m_ui_item.stackedWidget().tabCount());
emit ui_changed();
}
void UI_stacked_widget::from_json(const json &j)
{
UI_item::from_json(j);
m_tab_count = j.at("tab_count");
m_current_tab = j.at("current_tab");
}
json UI_stacked_widget::to_json(size_t id) const
{
json j = UI_item::to_json(id);
j["tab_count"] = m_tab_count;
j["current_tab"] = m_current_tab;
return j;
}
+3 -21
View File
@@ -22,41 +22,23 @@ class UI_stacked_widget : public UI_item
* @param current_tab The currently selected tab
* @param parent The parent QObject
*/
UI_stacked_widget(size_t tab_count, size_t current_tab, QObject *parent = nullptr);
UI_stacked_widget(qsizetype tab_count, qsizetype current_tab, QObject *parent = nullptr);
/**
* @brief Set the selected tab by index
*
* @param selected The index of the tab to select
*/
void set_selected(size_t selected) override;
void set_selected(qsizetype selected) override;
/**
* @brief Get the index of the selected tab
*
* @return size_t The index of the selected tab
*/
size_t selected() const;
qsizetype selected() const;
/**
* @brief Advance to the next tab
*
*/
void advance_tab();
/**
* @brief Deserialize the stacked widget from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the stacked widget to JSON
*
* @param id The id of the stacked widget
* @return json The JSON representation of the stacked widget
*/
json to_json(size_t id) const override;
private:
size_t m_tab_count;
size_t m_current_tab;
};
+14 -25
View File
@@ -1,44 +1,33 @@
#include "ui_status_bar.hpp"
UI_status_bar::UI_status_bar(QObject *parent) : UI_item(UI_enum::ui_status_bar, parent), m_timeout(0)
UI_status_bar::UI_status_bar(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_status_bar, parent)
{
setup_item(true, false, false);
m_ui_item.setStatusBar(UI_status_bar_m());
m_ui_item.statusBar().setTimeout(0);
}
UI_status_bar::UI_status_bar(std::string message, QObject *parent)
: UI_item(UI_enum::ui_status_bar, parent), m_timeout(0)
UI_status_bar::UI_status_bar(QString message, QObject *parent)
: UI_item(UI_typeGadget::UI_type::ui_status_bar, parent)
{
m_text = std::move(message);
setup_item(true, false, false);
m_ui_item.setStatusBar(UI_status_bar_m());
m_ui_item.statusBar().setMessage(message);
m_ui_item.statusBar().setTimeout(0);
}
void UI_status_bar::show_message(std::string message, size_t timeout)
void UI_status_bar::show_message(QString message, size_t timeout)
{
// This should work because the message gets only send once when it changes
m_text = std::move(message);
m_timeout = timeout;
m_ui_item.statusBar().setMessage(message);
m_ui_item.statusBar().setTimeout(timeout);
emit ui_changed();
}
std::string UI_status_bar::message() const &
QString UI_status_bar::message() const &
{
return m_text;
return m_ui_item.statusBar().message();
}
size_t UI_status_bar::timeout() const
{
return m_timeout;
}
void UI_status_bar::from_json(const json &j)
{
UI_item::from_json(j);
m_timeout = j.at("timeout");
}
json UI_status_bar::to_json(size_t id) const
{
json j = UI_item::to_json(id);
j["timeout"] = m_timeout;
return j;
return m_ui_item.statusBar().timeout();
}
+4 -21
View File
@@ -21,7 +21,7 @@ class UI_status_bar : public UI_item
* @param message The initial message
* @param parent The parent QObject
*/
UI_status_bar(std::string message, QObject *parent = nullptr);
UI_status_bar(QString message, QObject *parent = nullptr);
/**
* @brief Show a message on the status bar
@@ -29,34 +29,17 @@ class UI_status_bar : public UI_item
* @param message The message to show
* @param timeout The timeout in milliseconds (0 for no timeout)
*/
void show_message(std::string message, size_t timeout = 0);
void show_message(QString message, size_t timeout = 0);
/**
* @brief Get the current message
*
* @return std::string The current message
* @return QString The current message
*/
std::string message() const &;
QString message() const &;
/**
* @brief Get the timeout for the current message
*
* @return size_t The timeout in milliseconds
*/
size_t timeout() const;
/**
* @brief Deserialize the status bar from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the status bar to JSON
*
* @param id The id of the status bar
* @return json The JSON representation of the status bar
*/
json to_json(size_t id) const override;
private:
size_t m_timeout;
};
+32 -58
View File
@@ -1,104 +1,78 @@
#include "ui_tab_widget.hpp"
UI_tab_widget::UI_tab_widget(QObject *parent) : UI_item(UI_enum::ui_tab_widget, parent)
UI_tab_widget::UI_tab_widget(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_tab_widget, parent)
{
setup_item(false, false, false);
m_ui_item.setStackedWidget(UI_stacked_widget_m());
}
UI_tab_widget::UI_tab_widget(std::vector<std::string> tab_names, size_t selected, QObject *parent)
: UI_item(UI_enum::ui_tab_widget, parent), m_selected_tab(selected), m_tab_names(tab_names)
UI_tab_widget::UI_tab_widget(QList<QString> tab_names, qsizetype selected, QObject *parent)
: UI_item(UI_typeGadget::UI_type::ui_tab_widget, parent)
{
setup_item(false, false, false);
m_tab_visible.resize(m_tab_names.size(), true);
m_ui_item.setTabWidget(UI_tab_widget_m());
m_ui_item.tabWidget().setTabNames(tab_names);
m_ui_item.tabWidget().setSelecteTab(selected);
}
void UI_tab_widget::set_selected(size_t selected)
void UI_tab_widget::set_selected(qsizetype selected)
{
if (selected >= m_tab_names.size())
if (selected >= m_ui_item.tabWidget().tabNames().size())
return;
m_selected_tab = selected;
m_ui_item.tabWidget().setSelecteTab(selected);
emit ui_changed();
emit changed(m_selected_tab);
emit changed(selected);
}
size_t UI_tab_widget::selected() const
qsizetype UI_tab_widget::selected() const
{
return m_selected_tab;
return m_ui_item.tabWidget().selecteTab();
}
void UI_tab_widget::set_visible(size_t index, bool visible)
void UI_tab_widget::set_visible(qsizetype index, bool visible)
{
if (index >= m_tab_visible.size())
if (index >= m_ui_item.tabWidget().tabNames().size())
{
// Only allow known tab amount from constructor
return;
}
m_tab_visible.at(index) = visible;
auto list = m_ui_item.tabWidget().tabVisible();
list.replace(index, visible);
m_ui_item.tabWidget().setTabVisible(list);
emit ui_changed();
}
bool UI_tab_widget::visible(size_t index) const
bool UI_tab_widget::visible(qsizetype index) const
{
if (index >= m_tab_visible.size())
if (index >= m_ui_item.tabWidget().tabNames().size())
{
return false;
}
return m_tab_visible.at(index);
return m_ui_item.tabWidget().tabVisible().at(index);
}
void UI_tab_widget::set_tab_name(size_t index, std::string name)
void UI_tab_widget::set_tab_name(qsizetype index, QString name)
{
if (index >= m_tab_names.size() || index >= m_tab_visible.size())
if (index >= m_ui_item.tabWidget().tabNames().size() || index >= m_ui_item.tabWidget().tabVisible().size())
{
// Only allow known tab amount from constructor
return;
}
m_tab_names.at(index) = name;
auto list = m_ui_item.tabWidget().tabNames();
list.replace(index, name);
m_ui_item.tabWidget().setTabNames(list);
emit ui_changed();
}
std::string UI_tab_widget::tab_name(size_t index) const
QString UI_tab_widget::tab_name(qsizetype index) const
{
if (index >= m_tab_names.size())
if (index >= m_ui_item.tabWidget().tabNames().size())
{
return "";
}
return m_tab_names.at(index);
return m_ui_item.tabWidget().tabNames().at(index);
}
void UI_tab_widget::advance_tab()
{
if (m_tab_names.size() == 0)
if (m_ui_item.tabWidget().tabNames().empty())
return;
m_selected_tab = (m_selected_tab + 1) % m_tab_names.size();
m_ui_item.tabWidget().setSelecteTab((m_ui_item.tabWidget().selecteTab() + 1) % m_ui_item.tabWidget().tabNames().size());
emit ui_changed();
emit changed(m_selected_tab);
}
void UI_tab_widget::from_json(const json &j)
{
UI_item::from_json(j);
if (j.contains("tab_names"))
{
this->m_tab_names.clear();
for (auto &option : j["tab_names"])
{
this->m_tab_names.push_back(option);
}
}
if (j.contains("tab_visible"))
{
this->m_tab_visible.clear();
for (auto &option : j["tab_visible"])
{
this->m_tab_visible.push_back(option);
}
}
m_selected_tab = j.at("selected");
}
json UI_tab_widget::to_json(size_t id) const
{
json j = UI_item::to_json(id);
j["tab_names"] = m_tab_names;
j["tab_visible"] = m_tab_visible;
j["selected"] = m_selected_tab;
return j;
emit changed(m_ui_item.tabWidget().selecteTab());
}
+8 -27
View File
@@ -21,20 +21,20 @@ class UI_tab_widget : public UI_item
* @param selected The initially selected tab
* @param parent The parent QObject
*/
UI_tab_widget(std::vector<std::string> tab_names, size_t selected = 0, QObject *parent = nullptr);
UI_tab_widget(QList<QString> tab_names, qsizetype selected = 0, QObject *parent = nullptr);
/**
* @brief Set the selected tab by index
*
* @param selected The index of the tab to select
*/
void set_selected(size_t selected) override;
void set_selected(qsizetype selected) override;
/**
* @brief Get the index of the selected tab
*
* @return size_t The index of the selected tab
*/
size_t selected() const;
qsizetype selected() const;
/**
* @brief Set the visibility of a tab by index
@@ -42,7 +42,7 @@ class UI_tab_widget : public UI_item
* @param index The index of the tab
* @param visible True to show, false to hide
*/
void set_visible(size_t index, bool visible);
void set_visible(qsizetype index, bool visible);
/**
* @brief Get the visibility of a tab by index
*
@@ -50,7 +50,7 @@ class UI_tab_widget : public UI_item
* @return true If the tab is visible
* @return false If the tab is hidden
*/
bool visible(size_t index) const;
bool visible(qsizetype index) const;
/**
* @brief Set the name of a tab by index
@@ -58,44 +58,25 @@ class UI_tab_widget : public UI_item
* @param index The index of the tab
* @param name The name to set
*/
void set_tab_name(size_t index, std::string name);
void set_tab_name(qsizetype index, QString name);
/**
* @brief Get the name of a tab by index
*
* @param index The index of the tab
* @return std::string The name of the tab
*/
std::string tab_name(size_t index) const;
QString tab_name(qsizetype index) const;
/**
* @brief Advance to the next tab
*
*/
void advance_tab();
/**
* @brief Deserialize the tab widget from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the tab widget to JSON
*
* @param id The id of the tab widget
* @return json The JSON representation of the tab widget
*/
json to_json(size_t id) const override;
signals:
/**
* @brief Signal emitted when the selected tab changes
*
* @param index The index of the newly selected tab
*/
void changed(size_t index);
private:
size_t m_selected_tab;
std::vector<std::string> m_tab_names;
std::vector<bool> m_tab_visible;
void changed(qsizetype index);
};
+80 -74
View File
@@ -1,162 +1,168 @@
#include "ui_table.hpp"
UI_table::UI_table(QObject *parent) : UI_item(UI_enum::ui_table, parent), m_row_count(0), m_column_count(0)
UI_table::UI_table(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_table, parent)
{
setup_item(false, false, false);
m_ui_item.setTable(UI_table_m());
}
UI_table::UI_table(size_t row_count, size_t column_count, std::vector<std::string> row_labels,
std::vector<std::string> column_labels, QObject *parent)
: UI_item(UI_enum::ui_table, parent), m_row_count(row_count), m_column_count(column_count),
m_row_labels(row_labels), m_column_labels(column_labels), m_table()
UI_table::UI_table(qsizetype row_count, qsizetype column_count, QList<QString> row_labels,
QList<QString> column_labels, QObject *parent)
: UI_item(UI_typeGadget::UI_type::ui_table, parent)
{
setup_item(false, false, false);
m_row_labels.reserve(100);
m_column_labels.reserve(100);
m_table.reserve(500);
m_ui_item.setTable(UI_table_m());
m_ui_item.table().setRowCount(row_count);
m_ui_item.table().setColumnCount(column_count);
m_ui_item.table().setColumnLabels(column_labels);
m_ui_item.table().setRowLabels(row_labels);
}
void UI_table::set_row_count(size_t count)
void UI_table::set_row_count(qsizetype count)
{
m_row_count = count;
if (m_row_count != 0 || m_column_count != 0)
m_ui_item.table().setRowCount(count);
auto column_count = m_ui_item.table().columnCount();
auto row_count = m_ui_item.table().rowCount();
auto row_labels = m_ui_item.table().rowLabels();
if (row_count != 0 || column_count != 0)
{
m_table.resize(m_column_count * m_row_count);
auto table = m_ui_item.table().table();
table.resize(column_count * count);
m_ui_item.table().setTable(table);
}
m_row_labels.resize(m_row_count);
row_labels.resize(count);
m_ui_item.table().setRowLabels(row_labels);
emit ui_changed();
}
size_t UI_table::row_count() const
qsizetype UI_table::row_count() const
{
return m_row_count;
return m_ui_item.table().rowCount();
}
void UI_table::set_column_count(size_t count)
void UI_table::set_column_count(qsizetype count)
{
m_column_count = count;
if (m_row_count != 0 || m_column_count != 0)
m_ui_item.table().setColumnCount(count);
auto column_count = m_ui_item.table().columnCount();
auto row_count = m_ui_item.table().rowCount();
auto column_labels = m_ui_item.table().columnLabels();
if (row_count != 0 || column_count != 0)
{
m_table.resize(m_column_count * m_row_count);
auto table = m_ui_item.table().table();
table.resize(column_count * count);
m_ui_item.table().setTable(table);
}
m_column_labels.resize(m_column_count);
column_labels.resize(count);
m_ui_item.table().setColumnLabels(column_labels);
emit ui_changed();
}
size_t UI_table::column_count() const
qsizetype UI_table::column_count() const
{
return m_column_count;
return m_ui_item.table().columnCount();
}
size_t UI_table::capacity() const
qsizetype UI_table::capacity() const
{
return m_row_count * m_column_count;
return m_ui_item.table().rowCount() * m_ui_item.table().columnCount();
}
void UI_table::set_row_label(size_t index, std::string label)
void UI_table::set_row_label(qsizetype index, QString label)
{
if (m_row_count <= index)
if (m_ui_item.table().rowCount() <= index)
{
return;
}
m_row_labels[index] = std::move(label);
auto labels = m_ui_item.table().rowLabels();
labels.replace(index, label);
m_ui_item.table().setRowLabels(labels);
emit ui_changed();
}
std::string UI_table::row_label(size_t index) const
QString UI_table::row_label(qsizetype index) const
{
if (m_row_count <= index)
if (m_ui_item.table().rowCount() <= index)
{
return "";
}
return m_row_labels[index];
return m_ui_item.table().rowLabels().at(index);
}
void UI_table::set_column_label(size_t index, std::string label)
void UI_table::set_column_label(qsizetype index, QString label)
{
if (m_column_count <= index)
if (m_ui_item.table().columnCount() <= index)
{
return;
}
m_column_labels[index] = std::move(label);
auto labels = m_ui_item.table().columnLabels();
labels.replace(index, label);
m_ui_item.table().setColumnLabels(labels);
emit ui_changed();
}
std::string UI_table::column_label(size_t index) const &
QString UI_table::column_label(qsizetype index) const &
{
if (m_column_count <= index)
if (m_ui_item.table().columnCount() <= index)
{
return "";
}
return m_column_labels[index];
return m_ui_item.table().columnLabels().at(index);
}
void UI_table::insert_item(size_t row, size_t column, std::string text)
void UI_table::insert_item(qsizetype row, qsizetype column, QString text)
{
if (m_column_count <= column || m_row_count <= row)
if (m_ui_item.table().columnCount() <= column || m_ui_item.table().rowCount() <= row)
{
return;
}
if (capacity() > m_table.size())
if (capacity() > m_ui_item.table().table().size())
{
m_table.resize(capacity());
auto table = m_ui_item.table().table();
table.resize(capacity());
m_ui_item.table().setTable(table);
}
size_t index = row * m_column_count + column;
qsizetype index = row * m_ui_item.table().columnCount() + column;
m_table.at(index) = std::move(text);
auto table = m_ui_item.table().table();
table.replace(index, text);
m_ui_item.table().setTable(table);
emit ui_changed();
}
std::string UI_table::item(size_t row, size_t column) const &
QString UI_table::item(qsizetype row, qsizetype column) const &
{
if (m_column_count <= column || m_row_count <= row)
if (m_ui_item.table().columnCount() <= column || m_ui_item.table().rowCount() <= row)
{
return "";
}
size_t index = row * m_column_count + column;
qsizetype index = row * m_ui_item.table().columnCount() + column;
return m_table.at(index);
return m_ui_item.table().table().at(index);
}
void UI_table::empty_item(size_t row, size_t column)
void UI_table::empty_item(qsizetype row, qsizetype column)
{
size_t index = row * m_column_count + column;
if (m_ui_item.table().columnCount() <= column || m_ui_item.table().rowCount() <= row)
{
return;
}
qsizetype index = row * m_ui_item.table().columnCount() + column;
m_table[index] = "";
auto table = m_ui_item.table().table();
table.replace(index, "");
m_ui_item.table().setTable(table);
emit ui_changed();
}
void UI_table::from_json(const json &j)
{
UI_item::from_json(j);
this->m_row_count = j.at("row_count");
this->m_row_labels = j.at("row_labels");
this->m_column_count = j.at("column_count");
this->m_column_labels = j.at("column_labels");
this->m_table = j.at("table");
}
json UI_table::to_json(size_t id) const
{
json j = UI_item::to_json(id);
j["row_count"] = m_row_count;
j["row_labels"] = m_row_labels;
j["column_count"] = m_column_count;
j["column_labels"] = m_column_labels;
j["table"] = m_table;
return j;
}
+17 -39
View File
@@ -24,41 +24,41 @@ class UI_table : public UI_item
* @param column_labels The labels for the columns
* @param parent The parent QObject
*/
explicit UI_table(size_t row_count, size_t column_count, std::vector<std::string> row_labels,
std::vector<std::string> column_labels, QObject *parent = nullptr);
explicit UI_table(qsizetype row_count, qsizetype column_count, QList<QString> row_labels,
QList<QString> column_labels, QObject *parent = nullptr);
/**
* @brief Set the number of rows in the table
*
* @param count The number of rows
*/
void set_row_count(size_t count);
void set_row_count(qsizetype count);
/**
* @brief Get the number of rows in the table
*
* @return size_t The number of rows
*/
size_t row_count() const;
qsizetype row_count() const;
/**
* @brief Set the number of columns in the table
*
* @param count The number of columns
*/
void set_column_count(size_t count);
void set_column_count(qsizetype count);
/**
* @brief Get the number of columns in the table
*
* @return size_t The number of columns
*/
size_t column_count() const;
qsizetype column_count() const;
/**
* @brief Get the capacity of the table (rows * columns)
*
* @return size_t The capacity of the table
*/
size_t capacity() const;
qsizetype capacity() const;
/**
* @brief Set the label for a specific row
@@ -66,14 +66,14 @@ class UI_table : public UI_item
* @param index The index of the row
* @param label The label to set
*/
void set_row_label(size_t index, std::string label);
void set_row_label(qsizetype index, QString label);
/**
* @brief Get the label of a specific row
*
* @param index The index of the row
* @return std::string The label of the row
* @return QString The label of the row
*/
std::string row_label(size_t index) const;
QString row_label(qsizetype index) const;
/**
* @brief Set the label for a specific column
@@ -81,14 +81,14 @@ class UI_table : public UI_item
* @param index The index of the column
* @param label The label to set
*/
void set_column_label(size_t index, std::string label);
void set_column_label(qsizetype index, QString label);
/**
* @brief Get the label of a specific column
*
* @param index The index of the column
* @return std::string The label of the column
* @return QString The label of the column
*/
std::string column_label(size_t index) const &;
QString column_label(qsizetype index) const &;
/**
* @brief Insert an item into the table at the specified row and column
@@ -97,42 +97,20 @@ class UI_table : public UI_item
* @param column The column of the item
* @param text The text of the item
*/
void insert_item(size_t row, size_t column, std::string text);
void insert_item(qsizetype row, qsizetype column, QString text);
/**
* @brief Get the item at the specified row and column
*
* @param row The row of the item
* @param column The column of the item
* @return std::string The text of the item
* @return QString The text of the item
*/
std::string item(size_t row, size_t column) const &;
QString item(qsizetype row, qsizetype column) const &;
/**
* @brief empty_item This function clears the item
* @param row The row of the item
* @param column The column of the item
*/
void empty_item(size_t row, size_t column);
/**
* @brief Deserialize the table from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the table to JSON
*
* @param id The id of the table
* @return json The JSON representation of the table
*/
json to_json(size_t id) const override;
private:
size_t m_row_count;
size_t m_column_count;
std::vector<std::string> m_row_labels;
std::vector<std::string> m_column_labels;
std::vector<std::string> m_table;
void empty_item(qsizetype row, qsizetype column);
};
+41 -23
View File
@@ -1,43 +1,61 @@
#include "ui_textbox.hpp"
UI_textbox::UI_textbox(std::string hint, Color fg_color, Color bg_color, QObject *parent)
: UI_item(UI_enum::ui_textbox, "", fg_color, bg_color, parent), m_hint(hint)
UI_textbox::UI_textbox(QString hint, Color fg_color, Color bg_color, QObject *parent)
: UI_item(UI_typeGadget::UI_type::ui_textbox, parent)
{
m_ui_item.setTextbox(UI_textbox_m());
m_ui_item.textbox().setHint(hint);
m_ui_item.textbox().mutColor().setFgColor(fg_color.color());
m_ui_item.textbox().mutColor().setBgColor(bg_color.color());
}
UI_textbox::UI_textbox(QObject *parent) : UI_item(UI_enum::ui_textbox, parent)
UI_textbox::UI_textbox(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_textbox, parent)
{
m_ui_item.setTextbox(UI_textbox_m());
}
void UI_textbox::set_text(std::string text)
void UI_textbox::set_text(QString text)
{
if (text == m_text)
if (text == m_ui_item.textbox().text())
return;
m_text = std::move(text);
m_ui_item.textbox().setText(text);
emit ui_changed();
emit changed(m_text);
emit changed(m_ui_item.textbox().text());
}
void UI_textbox::set_hint(std::string hint)
QString UI_textbox::text() const
{
m_hint = std::move(hint);
return m_ui_item.label().text();
}
void UI_textbox::set_fg_color(Color color)
{
m_ui_item.label().mutColor().setFgColor(color.color());
}
Color UI_textbox::fg_color() const
{
return Color(m_ui_item.label().color().fgColor());
}
void UI_textbox::set_bg_color(Color color)
{
m_ui_item.label().mutColor().setBgColor(color.color());
}
Color UI_textbox::bg_color() const
{
return Color(m_ui_item.label().color().bgColor());
}
void UI_textbox::set_hint(QString hint)
{
m_ui_item.textbox().setHint(hint);
emit ui_changed();
}
std::string UI_textbox::hint() const &
QString UI_textbox::hint() const &
{
return m_hint;
return m_ui_item.textbox().hint();
}
void UI_textbox::from_json(const json &j)
{
UI_item::from_json(j);
m_hint = j.at("hint");
}
json UI_textbox::to_json(size_t id) const
{
json j = UI_item::to_json(id);
j["hint"] = m_hint;
return j;
}
+13 -23
View File
@@ -18,7 +18,7 @@ class UI_textbox : public UI_item
* @param bg_color The background color
* @param parent The parent QObject
*/
UI_textbox(std::string hint, Color fg_color, Color bg_color, QObject *parent = nullptr);
UI_textbox(QString hint, Color fg_color, Color bg_color, QObject *parent = nullptr);
/**
* @brief Construct a UI textbox object
*
@@ -31,42 +31,32 @@ class UI_textbox : public UI_item
*
* @param text The text to set
*/
void set_text(std::string text) override;
void set_text(QString text) override;
QString text() const;
void set_fg_color(Color fg_color);
Color fg_color() const;
void set_bg_color(Color bg_color);
Color bg_color() const;
/**
* @brief Get the hint text of the textbox
*
* @param hint The hint text to set
*/
void set_hint(std::string hint);
void set_hint(QString hint);
/**
* @brief Get the hint text of the textbox
*
* @return std::string The hint text
* @return QString The hint text
*/
std::string hint() const &;
/**
* @brief Deserialize the textbox from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the textbox to JSON
*
* @param id The id of the textbox
* @return json The JSON representation of the textbox
*/
json to_json(size_t id) const override;
QString hint() const &;
signals:
/**
* @brief Signal emitted when the text changes
*
* @param text The new text
*/
void changed(std::string text);
private:
std::string m_hint;
void changed(QString text);
};
+47 -83
View File
@@ -1,143 +1,107 @@
#include "ui_thermo.hpp"
UI_thermo::UI_thermo(std::string text, std::string unit, Color fg_color, Color bg_color, double min, double max,
UI_thermo::UI_thermo(QString text, QString unit, double min, double max,
double value, QObject *parent)
: UI_item(UI_enum::ui_thermo, text, fg_color, bg_color, parent), m_min(min), m_max(max), m_value(value),
m_unit(unit)
: UI_item(UI_typeGadget::UI_type::ui_thermo, parent)
{
m_ui_item.setRange(UI_range_m());
m_ui_item.range().setText(text);
m_ui_item.range().setUnit(unit);
m_ui_item.range().setMin(min);
m_ui_item.range().setMax(max);
m_ui_item.range().setValue(value);
}
UI_thermo::UI_thermo(std::string text, std::string unit, double min, double max, double value, QObject *parent)
: UI_thermo(text, unit, Color::Default, Color::Default, min, max, value, parent)
{
}
UI_thermo::UI_thermo(std::string text, Color fg_color, Color bg_color, double min, double max, double value,
UI_thermo::UI_thermo(QString text, double min, double max, double value,
QObject *parent)
: UI_thermo(text, "", fg_color, bg_color, min, max, value, parent)
: UI_thermo(text, "", min, max, value, parent)
{
}
UI_thermo::UI_thermo(std::string text, double min, double max, double value, QObject *parent)
: UI_thermo(text, "", Color::Default, Color::Default, min, max, value, parent)
{
}
UI_thermo::UI_thermo(QObject *parent) : UI_item(UI_enum::ui_thermo, parent)
UI_thermo::UI_thermo(QObject *parent) : UI_item(UI_typeGadget::UI_type::ui_thermo, parent)
{
}
void UI_thermo::set_value(double value)
{
if (value < m_min || value > m_max)
if (value < m_ui_item.range().min() || value > m_ui_item.range().max())
return;
if (value == m_value)
if (value == m_ui_item.range().value())
return;
this->m_value = value;
m_ui_item.range().setValue(value);
emit ui_changed();
}
double UI_thermo::value() const
{
return m_value;
return m_ui_item.range().value();
}
double UI_thermo::min() const
{
return m_min;
return m_ui_item.range().min();
}
double UI_thermo::max() const
{
return m_max;
return m_ui_item.range().max();
}
void UI_thermo::set_start_color(Color color)
{
this->m_color_map[0] = color;
emit ui_changed();
Q_UNUSED(color);
// this->m_color_map[0] = color;
// emit ui_changed();
}
void UI_thermo::set_end_color(Color color)
{
this->m_color_map[1] = color;
emit ui_changed();
Q_UNUSED(color);
// this->m_color_map[1] = color;
// emit ui_changed();
}
void UI_thermo::add_color_stop(double value, Color color)
{
if (value <= 0 || value >= 1)
return;
Q_UNUSED(value);
Q_UNUSED(color);
// if (value <= 0 || value >= 1)
// return;
this->m_color_map[value] = color;
emit ui_changed();
// this->m_color_map[value] = color;
// emit ui_changed();
}
void UI_thermo::add_color_stop_normalized(double value, Color color)
{
if (value < m_min || value > m_max)
return;
Q_UNUSED(value);
Q_UNUSED(color);
// if (value < m_min || value > m_max)
// return;
double normalized = (value - m_min) / (m_max - m_min);
this->m_color_map[normalized] = color;
emit ui_changed();
// double normalized = (value - m_min) / (m_max - m_min);
// this->m_color_map[normalized] = color;
// emit ui_changed();
}
void UI_thermo::remove_color_stop(double value)
{
if (value <= 0 || value >= 1)
return;
Q_UNUSED(value);
// if (value <= 0 || value >= 1)
// return;
this->m_color_map.erase(value);
emit ui_changed();
// this->m_color_map.erase(value);
// emit ui_changed();
}
void UI_thermo::remove_color_stop_normalized(double value)
{
if (value < m_min || value > m_max)
return;
Q_UNUSED(value);
// if (value < m_min || value > m_max)
// return;
double normalized = (value - m_min) / (m_max - m_min);
this->m_color_map.erase(normalized);
emit ui_changed();
}
void UI_thermo::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");
this->m_unit = j.at("unit");
this->m_color_map.clear();
if (!j.contains("color_map"))
return;
for (auto &i : j["color_map"])
{
double k = i.at("key");
std::string c = i.at("value");
this->m_color_map[k] = Color(c);
}
}
json UI_thermo::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;
j["unit"] = this->m_unit;
if (this->m_color_map.empty())
return j;
j["color_map"] = json::array();
for (auto &[key, value] : this->m_color_map)
{
json item = json::object();
item["key"] = key;
item["value"] = value.to_hex();
j["color_map"].push_back(item);
}
return j;
// double normalized = (value - m_min) / (m_max - m_min);
// this->m_color_map.erase(normalized);
// emit ui_changed();
}
+2 -46
View File
@@ -15,26 +15,13 @@ class UI_thermo : public UI_item
*
* @param text The text to display
* @param unit The unit of the thermometer
* @param fg_color The foreground color
* @param bg_color The background color
* @param min The minimum value
* @param max The maximum value
* @param value The initial value
* @param parent The parent QObject
*/
UI_thermo(std::string text, std::string unit, Color fg_color, Color bg_color, double min, double max, double value,
UI_thermo(QString text, QString unit, double min, double max, double value,
QObject *parent = nullptr);
/**
* @brief Construct a UI thermometer object
*
* @param text The text to display
* @param unit The unit of the thermometer
* @param min The minimum value
* @param max The maximum value
* @param value The initial value
* @param parent The parent QObject
*/
UI_thermo(std::string text, std::string unit, double min, double max, double value, QObject *parent = nullptr);
/**
* @brief Construct a UI thermometer object
*
@@ -46,18 +33,8 @@ class UI_thermo : public UI_item
* @param value The initial value
* @param parent The parent QObject
*/
UI_thermo(std::string text, Color fg_color, Color bg_color, double min, double max, double value,
UI_thermo(QString text, double min, double max, double value,
QObject *parent = nullptr);
/**
* @brief Construct a UI thermometer object
*
* @param text The text to display
* @param min The minimum value
* @param max The maximum value
* @param value The initial value
* @param parent The parent QObject
*/
UI_thermo(std::string text, double min, double max, double value, QObject *parent = nullptr);
/**
* @brief Construct a UI thermometer object
*
@@ -129,25 +106,4 @@ class UI_thermo : public UI_item
* @param value The normalized value (0.0 to 1.0) of the color stop to remove
*/
void remove_color_stop_normalized(double value);
/**
* @brief Deserialize the thermometer from JSON
*
* @param j The JSON object
*/
void from_json(const json &j) override;
/**
* @brief Serialize the thermometer to JSON
*
* @param id The id of the thermometer
* @return json The JSON representation of the thermometer
*/
json to_json(size_t id) const override;
private:
double m_min;
double m_max;
double m_value;
std::string m_unit;
std::unordered_map<double, Color> m_color_map;
};
+3 -6
View File
@@ -1,5 +1,5 @@
find_package(QT NAMES Qt6 REQUIRED COMPONENTS Widgets Svg WebSockets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Svg WebSockets)
find_package(QT NAMES Qt6 REQUIRED COMPONENTS Widgets Svg Protobuf Grpc)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Svg Protobuf Grpc)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
@@ -19,8 +19,6 @@ set(PROJECT_SOURCES
helpers.hpp
ui_base.cpp
ui_base.hpp
web_socket_wrapper.cpp
web_socket_wrapper.hpp
)
qt_add_executable(unisim_client
@@ -31,7 +29,6 @@ set_target_properties(
unisim_client
PROPERTIES
AUTOMOC ON
AUTORCC ON
AUTOUIC ON
)
@@ -43,7 +40,7 @@ target_include_directories(unisim_client
${PROJECT_BINARY_DIR}/
)
target_link_libraries(unisim_client PUBLIC Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::WebSockets spdlog magic_enum::magic_enum nlohmann_json::nlohmann_json git_tag qwt UI_enum)
target_link_libraries(unisim_client PUBLIC Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Protobuf Qt${QT_VERSION_MAJOR}::Grpc spdlog magic_enum::magic_enum qwt git_tag proto-ui-client)
include(GNUInstallDirs)
install(TARGETS unisim_client
+4 -4
View File
@@ -9,7 +9,7 @@
class UIFactory
{
public:
using Creator = std::function<UI_base *(Web_socket_wrapper *web_socket, QWidget *)>;
using Creator = std::function<UI_base *(RemoteUiService::Client *s, QWidget *)>;
static UIFactory &instance()
{
@@ -25,12 +25,12 @@ class UIFactory
return true;
}
UI_base *create(const QString &key, Web_socket_wrapper *w, QWidget *parent = nullptr) const
UI_base *create(const QString &key, RemoteUiService::Client *s, QWidget *parent = nullptr) const
{
auto it = m_creators.constFind(key);
if (it == m_creators.cend())
return nullptr;
return it.value()(w, parent);
return it.value()(s, parent);
}
QStringList keys() const
@@ -50,7 +50,7 @@ class UIFactory
Register##TYPE() \
{ \
UIFactory::instance().registerType(TYPE::name(), \
[](Web_socket_wrapper *w, QWidget *p) { return new TYPE(w, p); }); \
[](RemoteUiService::Client *s, QWidget *p) { return new TYPE(s, p); }); \
} \
}; \
static Register##TYPE register_##TYPE; \
+71 -56
View File
@@ -3,33 +3,35 @@
#include "git_version.h"
#include "ui_base.hpp"
#include "ui_mainwindow.h"
#include "web_socket_wrapper.hpp"
#include "messages_client.grpc.qpb.h"
#include <QDirIterator>
#include <QLibrary>
#include <QMessageBox>
#include <QThread>
#include <QTimer>
#include <magic_enum/magic_enum.hpp>
#include <spdlog/spdlog.h>
#include <QGrpcHttp2Channel>
#include <QGrpcChannelOptions>
#include <QSslConfiguration>
#include <QSslSocket>
MainWindow::MainWindow(QUrl ws_url, QString sim, QWidget *parent)
typedef UI_base *(*Get_UI)(RemoteUiService::Client *, QWidget *);
MainWindow::MainWindow(QUrl server_url, QString sim, QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow), m_error(new QMessageBox()),
m_web_socket(new Web_socket_wrapper(ws_url))
m_remote_ui_client(new RemoteUiService::Client()), m_ping(new QTimer())
{
ui->setupUi(this);
ui->statusbar->showMessage(QString("Version: %1-%2%3")
.arg(Git_version::branch)
.arg(Git_version::shortSha1)
.arg(Git_version::dirty ? "-dirty" : ""));
connect(m_web_socket.get(), &Web_socket_wrapper::log_signal, this,
[](const char *filename_in, int line_in, const char *funcname_in, int level, QString msg) {
if (spdlog::default_logger_raw()->should_log((spdlog::level::level_enum)level))
spdlog::default_logger_raw()->log(spdlog::source_loc{filename_in, line_in, funcname_in},
(spdlog::level::level_enum)level, msg.toStdString());
});
m_ping->setInterval(std::chrono::milliseconds(1000));
for (const QString &name : UIFactory::instance().keys())
{
if (auto *w = UIFactory::instance().create(name, m_web_socket.get(), this))
if (auto *w = UIFactory::instance().create(name, m_remote_ui_client.get(), this))
{
w->set_name(name);
m_sims.insert(std::make_pair(name, w));
@@ -42,9 +44,6 @@ MainWindow::MainWindow(QUrl ws_url, QString sim, QWidget *parent)
}
}
// Insert debug sims here
// INSERT_SIMULATOR(SIM_NAME);
setWindowTitle("Unisim cpp client");
m_error->setIcon(QMessageBox::Critical);
m_error->setWindowTitle("Critical");
@@ -52,12 +51,42 @@ MainWindow::MainWindow(QUrl ws_url, QString sim, QWidget *parent)
QPushButton *exit_app = m_error->addButton("Exit Application", QMessageBox::AcceptRole);
m_error->addButton("Close", QMessageBox::RejectRole);
connect(exit_app, &QPushButton::clicked, this, &QCoreApplication::quit, Qt::QueuedConnection);
ui->connection->setText("Connected to " + ws_url.toString());
ui->connection->setText("Connected to " + server_url.toString());
// Default sim
if (!sim.isEmpty())
default_sim(sim);
QSslConfiguration ssl_config = QSslConfiguration::defaultConfiguration();
// Required for HTTP/2
ssl_config.setAllowedNextProtocols({ "h2" });
// Disable certificate verification
ssl_config.setPeerVerifyMode(QSslSocket::VerifyNone);
QGrpcChannelOptions options;
options.setSslConfiguration(ssl_config);
server_url.setScheme("https");
auto channel = std::make_shared<QGrpcHttp2Channel>(server_url, options);
m_remote_ui_client->attachChannel(channel);
connect(ui->pushButton, &QPushButton::clicked, this, [=, this] { open_sim(ui->comboBox->currentText()); });
connect(m_ping, &QTimer::timeout, this, [this]{
// TODO: find a way to check if the channel is open
});
connect(this, &MainWindow::on_show_event, this, [this]{
auto reply = m_remote_ui_client->Command_get_simulators(Empty());
connect(reply.get(), &QGrpcCallReply::finished, this, [this, reply = reply.get()](const QGrpcStatus &status) {
auto response = reply->read<Simulators_m>();
if (!response.has_value() || !status.isOk())
{
SPDLOG_CRITICAL("Command get simulators has got no response");
return;
}
pase_sim_names(response.value());
}, Qt::SingleShotConnection);
}, Qt::SingleShotConnection);
}
MainWindow::~MainWindow()
@@ -68,19 +97,14 @@ MainWindow::~MainWindow()
void MainWindow::showEvent(QShowEvent *event)
{
QWidget::showEvent(event);
connect(m_web_socket.get(), &Web_socket_wrapper::on_command_cb, this, [=, this](json &j) { on_cmd_cb(j); });
connect(m_web_socket.get(), &Web_socket_wrapper::on_connected, this,
[=, this] { m_web_socket->send_command(Web_socket_wrapper::Command::get_simulators); });
connect(m_web_socket.get(), &Web_socket_wrapper::on_closed, this, [=, this] {
m_error->open();
ui->connection->setText("Could not connect to the server");
});
emit on_show_event();
m_ping->start();
}
void MainWindow::hideEvent(QHideEvent *event)
{
QWidget::hideEvent(event);
disconnect(m_web_socket.get(), nullptr, nullptr, nullptr);
disconnect(m_remote_ui_client.get(), nullptr, nullptr, nullptr);
}
void MainWindow::default_sim(QString name)
@@ -89,12 +113,11 @@ void MainWindow::default_sim(QString name)
this->m_default_sim = true;
}
void MainWindow::pase_sim_names(json &sims)
void MainWindow::pase_sim_names(Simulators_m &sims)
{
for (json &item : sims)
for (auto &item : sims.simulator())
{
if (m_sims.contains(QString::fromStdString(item)))
ui->comboBox->addItem(QString::fromStdString(item));
ui->comboBox->addItem(item);
}
QThread::msleep(30);
@@ -119,7 +142,18 @@ void MainWindow::open_sim(QString sim_name)
return;
}
m_web_socket->send_command(Web_socket_wrapper::Command::get_active_simulator_name);
auto cmd = Simulator_m();
cmd.setSimuator(sim_name);
auto reply = m_remote_ui_client->Command_switch_simulator(cmd);
connect(reply.get(), &QGrpcCallReply::finished, this, [this, reply = reply.get()] {
auto response = reply->read<Empty>();
if (!response.has_value())
{
qDebug("Switch simulator deserialization failed");
return;
}
open_sim_window();
}, Qt::SingleShotConnection);
}
void MainWindow::open_sim_window(void)
@@ -130,15 +164,6 @@ void MainWindow::open_sim_window(void)
void MainWindow::check_active_sim(QString name)
{
if (name == "")
{
SPDLOG_DEBUG("Name not set");
m_web_socket->send_command(Web_socket_wrapper::Command::switch_simulator, m_selected_sim_name);
return;
}
SPDLOG_DEBUG("Current sim:", name);
if (name == m_selected_sim_name)
{
SPDLOG_DEBUG("Name set and the same");
@@ -146,26 +171,16 @@ void MainWindow::check_active_sim(QString name)
return;
}
SPDLOG_DEBUG("Name set and wrong");
m_web_socket->send_command(Web_socket_wrapper::Command::switch_simulator, m_selected_sim_name);
auto cmd = Simulator_m();
cmd.setSimuator(m_selected_sim_name);
auto reply = m_remote_ui_client->Command_switch_simulator(cmd);
connect(reply.get(), &QGrpcCallReply::finished, this, [this, reply = reply.get()] {
auto response = reply->read<Empty>();
if (!response.has_value())
{
qDebug("Switch simulator deserialization failed");
return;
}
void MainWindow::on_cmd_cb(json &j)
{
auto response = magic_enum::enum_cast<Web_socket_wrapper::Command>(std::string(j.at("type")))
.value_or(Web_socket_wrapper::Command::end);
switch (response)
{
case Web_socket_wrapper::Command::get_simulators:
pase_sim_names(j.at("simulators"));
break;
case Web_socket_wrapper::Command::get_active_simulator_name:
check_active_sim(QString::fromStdString(j.at("name")));
break;
case Web_socket_wrapper::Command::switch_simulator:
open_sim_window();
break;
default:
break;
}
}, Qt::SingleShotConnection);
}
+16 -13
View File
@@ -1,16 +1,23 @@
#pragma once
#include "nlohmann/json.hpp"
#include <QMainWindow>
#include <map>
using json = nlohmann::json;
#include "messages.qpb.h"
#define INSERT_SIMULATOR(type) \
m_sims.insert(std::make_pair(type().sim_name(), std::make_unique<type>(m_web_socket.get(), this)))
Q_FORWARD_DECLARE_OBJC_CLASS(QMessageBox);
Q_FORWARD_DECLARE_OBJC_CLASS(Web_socket_wrapper);
Q_FORWARD_DECLARE_OBJC_CLASS(UI_base);
Q_FORWARD_DECLARE_OBJC_CLASS(QTimer);
namespace RemoteUiService
{
class Client;
}
namespace Health
{
class Client;
}
namespace Ui
{
@@ -32,6 +39,8 @@ class MainWindow : public QMainWindow
explicit MainWindow(QUrl ws_url, QString sim, QWidget *parent = nullptr);
~MainWindow();
signals:
void on_show_event();
private:
/**
* @brief Handle the show event
@@ -59,7 +68,7 @@ class MainWindow : public QMainWindow
*
* @param sims The JSON array of simulator names
*/
void pase_sim_names(json &sims);
void pase_sim_names(Simulators_m &sims);
/**
* @brief Open the simulator window using the selected simulator
*/
@@ -78,18 +87,12 @@ class MainWindow : public QMainWindow
*/
void open_sim(QString sim_name);
/**
* @brief Handle command callbacks from the server
*
* @param j The JSON command
*/
void on_cmd_cb(json &j);
bool m_default_sim = false;
QString m_selected_sim_name;
QMainWindow *m_selected_sim;
QMessageBox *m_error;
Ui::MainWindow *ui;
std::unique_ptr<Web_socket_wrapper> m_web_socket;
std::unique_ptr<RemoteUiService::Client> m_remote_ui_client;
std::map<QString, std::unique_ptr<UI_base>> m_sims;
QTimer *m_ping;
};
+1 -1
View File
@@ -4,7 +4,7 @@
REGISTER_UI(Can_Debugger);
Can_Debugger::Can_Debugger(Web_socket_wrapper *web_socket, QWidget *parent)
Can_Debugger::Can_Debugger(RemoteUiService::Client *web_socket, QWidget *parent)
: UI_base(web_socket, parent), ui(new Ui::Can_Debugger)
{
ui->setupUi(this);
+1 -1
View File
@@ -11,7 +11,7 @@ class Can_Debugger : public UI_base
Q_OBJECT
public:
explicit Can_Debugger(Web_socket_wrapper *web_socket = nullptr, QWidget *parent = nullptr);
explicit Can_Debugger(RemoteUiService::Client *web_socket = nullptr, QWidget *parent = nullptr);
~Can_Debugger();
static QString name()
{
+1 -1
View File
@@ -4,7 +4,7 @@
REGISTER_UI(Test_Sim);
Test_Sim::Test_Sim(Web_socket_wrapper *web_socket, QWidget *parent) : UI_base(web_socket, parent), ui(new Ui::Test_Sim)
Test_Sim::Test_Sim(RemoteUiService::Client *web_socket, QWidget *parent) : UI_base(web_socket, parent), ui(new Ui::Test_Sim)
{
ui->setupUi(this);
+1 -1
View File
@@ -11,7 +11,7 @@ class Test_Sim : public UI_base
Q_OBJECT
public:
explicit Test_Sim(Web_socket_wrapper *web_socket = nullptr, QWidget *parent = nullptr);
explicit Test_Sim(RemoteUiService::Client *web_socket = nullptr, QWidget *parent = nullptr);
~Test_Sim();
static QString name()
+7 -7
View File
@@ -15,11 +15,11 @@ Can_Transceive::Can_Transceive(QWidget *parent) : QWidget(parent), ui(new Ui::Ca
connect(ui->b_can_send_send, &QPushButton::clicked, this, [=, this] {
emit send_can_message(
ui->s_can_send_sid->value(), ui->c_can_send_dlc->currentIndex(),
std::array<uint8_t, 8>(
{(uint8_t)(can_send_hexspinboxes[0]->value()), (uint8_t)(can_send_hexspinboxes[1]->value()),
(uint8_t)(can_send_hexspinboxes[2]->value()), (uint8_t)(can_send_hexspinboxes[3]->value()),
(uint8_t)(can_send_hexspinboxes[4]->value()), (uint8_t)(can_send_hexspinboxes[5]->value()),
(uint8_t)(can_send_hexspinboxes[6]->value()), (uint8_t)(can_send_hexspinboxes[7]->value())}));
QByteArray().append((uint8_t)(can_send_hexspinboxes[0]->value())).append((uint8_t)(can_send_hexspinboxes[0]->value()))
.append((uint8_t)(can_send_hexspinboxes[1]->value())).append((uint8_t)(can_send_hexspinboxes[2]->value()))
.append((uint8_t)(can_send_hexspinboxes[3]->value())).append((uint8_t)(can_send_hexspinboxes[4]->value()))
.append((uint8_t)(can_send_hexspinboxes[5]->value())).append((uint8_t)(can_send_hexspinboxes[6]->value()))
.append((uint8_t)(can_send_hexspinboxes[7]->value())));
});
connect(ui->b_clear, &QPushButton::clicked, this, [=, this] { emit can_clear(); });
}
@@ -48,7 +48,7 @@ void Can_Transceive::clear()
ui->send_list->setRowCount(0);
}
void Can_Transceive::add_send_item(uint32_t id, uint8_t dlc, std::array<uint8_t, 8> payload)
void Can_Transceive::add_send_item(uint32_t id, uint8_t dlc, QByteArray payload)
{
size_t rc = ui->send_list->rowCount();
ui->send_list->setRowCount(rc + 1);
@@ -62,7 +62,7 @@ void Can_Transceive::add_send_item(uint32_t id, uint8_t dlc, std::array<uint8_t,
ui->send_list->resizeColumnsToContents();
}
void Can_Transceive::add_receive_item(uint32_t id, uint8_t dlc, std::array<uint8_t, 8> payload)
void Can_Transceive::add_receive_item(uint32_t id, uint8_t dlc, QByteArray payload)
{
size_t rc = ui->recvd_list->rowCount();
ui->recvd_list->setRowCount(rc + 1);
+3 -3
View File
@@ -47,7 +47,7 @@ class Can_Transceive : public QWidget
* @param dlc The Data Length Code
* @param payload The CAN message payload
*/
void add_send_item(uint32_t id, uint8_t dlc, std::array<uint8_t, 8> payload);
void add_send_item(uint32_t id, uint8_t dlc, QByteArray payload);
/**
* @brief Add a received CAN message to the receive list
@@ -56,7 +56,7 @@ class Can_Transceive : public QWidget
* @param dlc The Data Length Code
* @param payload The CAN message payload
*/
void add_receive_item(uint32_t id, uint8_t dlc, std::array<uint8_t, 8> payload);
void add_receive_item(uint32_t id, uint8_t dlc, QByteArray payload);
signals:
/**
@@ -66,7 +66,7 @@ class Can_Transceive : public QWidget
* @param dlc The Data Length Code
* @param payload The CAN message payload
*/
void send_can_message(uint32_t id, uint8_t dlc, std::array<uint8_t, 8> payload);
void send_can_message(uint32_t id, uint8_t dlc, QByteArray payload);
/**
* @brief Emitted when the CAN message lists are to be cleared
+227 -181
View File
@@ -3,12 +3,12 @@
#include "helpers.hpp"
#include "led.hpp"
#include "plot_wrapper.hpp"
#include "web_socket_wrapper.hpp"
#include <QMessageBox>
#include <magic_enum/magic_enum.hpp>
#include "messages_client.grpc.qpb.h"
UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
: QMainWindow{parent}, m_timer_update(new QTimer()), m_error(new QMessageBox(this)), m_web_socket(web_socket)
UI_base::UI_base(RemoteUiService::Client *remote_ui_client, QWidget *parent)
: QMainWindow{parent}, m_timer_update(new QTimer()), m_error(new QMessageBox(this)), m_remote_ui_client(remote_ui_client)
{
this->setWindowState(Qt::WindowMaximized);
m_ui_lookup.reserve(40);
@@ -19,7 +19,8 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
QPushButton *exit_app = m_error->addButton("Exit Application", QMessageBox::AcceptRole);
m_error->addButton("Close", QMessageBox::RejectRole);
connect(exit_app, &QPushButton::clicked, this, &QCoreApplication::quit, Qt::QueuedConnection);
m_process_lookup.insert(UI_enum::ui_label, [=, this](json &ui_item, QWidget *widget) {
m_process_lookup.insert(UI_typeGadget::UI_type::ui_label, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto label = qobject_cast<QLabel *>(widget);
if (label == nullptr)
{
@@ -27,9 +28,9 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
QString value = QString::fromStdString(ui_item.at("text"));
bool enabled = ui_item.at("enabled");
bool visible = ui_item.at("visible");
QString value = ui_item.label().text();
bool enabled = ui_item.enabled();
bool visible = ui_item.visible();
if (label->isEnabled() != enabled)
{
@@ -47,8 +48,8 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
}
});
m_process_lookup.insert(UI_enum::ui_slider, [=, this](json &ui_item, QWidget *widget) {
QLabel *label = id_to_label(id_to_ui(ui_item.at("id")));
m_process_lookup.insert(UI_typeGadget::UI_type::ui_slider, [=, this](const UI_item_m &ui_item, QWidget *widget) {
QLabel *label = id_to_label(id_to_ui(ui_item.id_proto()));
auto slider = qobject_cast<QwtSlider *>(widget);
if (slider == nullptr)
{
@@ -56,10 +57,10 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
double value = ui_item.at("value");
bool enable = ui_item.at("enabled");
bool visible = ui_item.at("visible");
QString unit = QString::fromStdString(ui_item.at("unit"));
double value = ui_item.range().value();
bool enable = ui_item.enabled();
bool visible = ui_item.visible();
QString unit = ui_item.range().unit();
if (label != nullptr)
{
@@ -82,8 +83,8 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
}
// TODO: Add color for scale
});
m_process_lookup.insert(UI_enum::ui_dial, [=, this](json &ui_item, QWidget *widget) {
QLabel *label = id_to_label(id_to_ui(ui_item.at("id")));
m_process_lookup.insert(UI_typeGadget::UI_type::ui_dial, [=, this](const UI_item_m &ui_item, QWidget *widget) {
QLabel *label = id_to_label(id_to_ui(ui_item.id_proto()));
auto dial = qobject_cast<QwtDial *>(widget);
if (dial == nullptr)
{
@@ -91,9 +92,9 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
double value = ui_item.at("value");
bool visible = ui_item.at("visible");
QString unit = QString::fromStdString(ui_item.at("unit"));
double value = ui_item.range().value();
bool visible = ui_item.visible();
QString unit = ui_item.range().unit();
if (label != nullptr)
{
@@ -110,8 +111,8 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
dial->setVisible(visible);
}
});
m_process_lookup.insert(UI_enum::ui_thermo, [=, this](json &ui_item, QWidget *widget) {
QLabel *label = id_to_label(id_to_ui(ui_item.at("id")));
m_process_lookup.insert(UI_typeGadget::UI_type::ui_thermo, [=, this](const UI_item_m &ui_item, QWidget *widget) {
QLabel *label = id_to_label(id_to_ui(ui_item.id_proto()));
auto thermo = qobject_cast<QwtThermo *>(widget);
if (thermo == nullptr)
{
@@ -119,9 +120,9 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
double value = ui_item.at("value");
bool visible = ui_item.at("visible");
QString unit = QString::fromStdString(ui_item.at("unit"));
double value = ui_item.range().value();
bool visible = ui_item.visible();
QString unit = ui_item.range().unit();
if (label != nullptr)
{
@@ -138,7 +139,7 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
thermo->setVisible(visible);
}
});
m_process_lookup.insert(UI_enum::ui_textbox, [=, this](json &ui_item, QWidget *widget) {
m_process_lookup.insert(UI_typeGadget::UI_type::ui_textbox, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto line_edit = qobject_cast<QLineEdit *>(widget);
if (line_edit == nullptr)
{
@@ -146,10 +147,10 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
bool visible = ui_item.at("visible");
bool enabled = ui_item.at("enabled");
QString hint = QString::fromStdString(ui_item.at("hint"));
QString text = QString::fromStdString(ui_item.at("text"));
bool visible = ui_item.visible();
bool enabled = ui_item.enabled();
QString hint = ui_item.textbox().hint();
QString text = ui_item.textbox().text();
if (line_edit->isVisible() != visible)
{
@@ -169,7 +170,7 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
line_edit->setText(text);
}
});
m_process_lookup.insert(UI_enum::ui_combobox, [=, this](json &ui_item, QWidget *widget) {
m_process_lookup.insert(UI_typeGadget::UI_type::ui_combobox, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto combobox = qobject_cast<QComboBox *>(widget);
if (combobox == nullptr)
{
@@ -177,9 +178,9 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
size_t selected = ui_item.at("selected");
bool enabled = ui_item.at("enabled");
bool visible = ui_item.at("visible");
size_t selected = ui_item.combobox().selected();
bool enabled = ui_item.enabled();
bool visible = ui_item.visible();
if (combobox->isEnabled() != enabled)
{
@@ -191,10 +192,10 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
combobox->setVisible(visible);
}
for (json &item : ui_item.at("options"))
for (const QString &item : ui_item.combobox().options())
{
if (combobox->findText(QString::fromStdString(item)) == -1)
combobox->addItem(QString::fromStdString(item));
if (combobox->findText(item) == -1)
combobox->addItem(item);
}
if (combobox->currentIndex() != selected)
@@ -202,9 +203,9 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
combobox->setCurrentIndex(selected);
}
});
// m_process_lookup.insert(UI_enum::ui_radiobutton,
// [=, this](json &ui_item, QWidget *widget) { LOG_CRITICAL("Not implemented"); });
m_process_lookup.insert(UI_enum::ui_checkbox, [=, this](json &ui_item, QWidget *widget) {
// m_process_lookup.insert(UI_typeGadget::UI_type::ui_radiobutton,
// [=, this](const UI_item_m &ui_item, QWidget *widget) { LOG_CRITICAL("Not implemented"); });
m_process_lookup.insert(UI_typeGadget::UI_type::ui_checkbox, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto checkbox = qobject_cast<QCheckBox *>(widget);
if (checkbox == nullptr)
{
@@ -212,12 +213,12 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
QColor bg_color = QColor(QString::fromStdString(ui_item.at("bg_color")));
QColor fg_color = QColor(QString::fromStdString(ui_item.at("fg_color")));
QString text = QString::fromStdString(ui_item.at("text"));
bool enabled = ui_item.at("enabled");
bool visible = ui_item.at("visible");
bool checked = ui_item.at("checked");
QColor bg_color = QColor(ui_item.checkbox().color().bgColor());
QColor fg_color = QColor(ui_item.checkbox().color().fgColor());
QString text = ui_item.checkbox().text();
bool enabled = ui_item.enabled();
bool visible = ui_item.visible();
bool checked = ui_item.checkbox().checked();
if (checkbox->isChecked() != checked)
{
@@ -268,7 +269,7 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
set_widget_color(checkbox, fg_color, bg_color);
}
});
m_process_lookup.insert(UI_enum::ui_button, [=, this](json &ui_item, QWidget *widget) {
m_process_lookup.insert(UI_typeGadget::UI_type::ui_button, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto button = qobject_cast<QPushButton *>(widget);
if (button == nullptr)
{
@@ -276,11 +277,11 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
QColor bg_color = QColor(QString::fromStdString(ui_item.at("bg_color")));
QColor fg_color = QColor(QString::fromStdString(ui_item.at("fg_color")));
QString text = QString::fromStdString(ui_item.at("text"));
bool enabled = ui_item.at("enabled");
bool visible = ui_item.at("visible");
QColor bg_color = QColor(ui_item.label().color().bgColor());
QColor fg_color = QColor(ui_item.label().color().fgColor());
QString text = ui_item.label().text();
bool enabled = ui_item.enabled();
bool visible = ui_item.visible();
if (button->isEnabled() != enabled)
{
@@ -326,7 +327,7 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
set_widget_color(button, fg_color, bg_color);
}
});
m_process_lookup.insert(UI_enum::ui_led, [=, this](json &ui_item, QWidget *widget) {
m_process_lookup.insert(UI_typeGadget::UI_type::ui_led, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto led = qobject_cast<Led *>(widget);
if (led == nullptr)
{
@@ -334,10 +335,10 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
QColor bg_color = QColor(QString::fromStdString(ui_item.at("bg_color")));
QColor color = QColor(QString::fromStdString(ui_item.at("fg_color")));
QString text = QString::fromStdString(ui_item.at("text"));
bool visible = ui_item.at("visible");
QColor bg_color = QColor(ui_item.label().color().bgColor());
QColor color = QColor(ui_item.label().color().fgColor());
QString text = ui_item.label().text();
bool visible = ui_item.visible();
if (led->isVisible() != visible)
{
@@ -378,7 +379,7 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
set_widget_color(led, color, bg_color);
}
});
m_process_lookup.insert(UI_enum::ui_spinbox, [=, this](json &ui_item, QWidget *widget) {
m_process_lookup.insert(UI_typeGadget::UI_type::ui_spinbox, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto spinbox = qobject_cast<QSpinBox *>(widget);
if (spinbox == nullptr)
{
@@ -386,11 +387,11 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
bool enabled = ui_item.at("enabled");
bool visible = ui_item.at("visible");
double min = ui_item.at("min");
double max = ui_item.at("max");
double value = ui_item.at("value");
bool enabled = ui_item.enabled();
bool visible = ui_item.visible();
double min = ui_item.range().min();
double max = ui_item.range().max();
double value = ui_item.range().value();
if (enabled != spinbox->isEnabled())
{
@@ -415,7 +416,7 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
spinbox->setValue((int)value);
}
});
m_process_lookup.insert(UI_enum::ui_double_spinbox, [=, this](json &ui_item, QWidget *widget) {
m_process_lookup.insert(UI_typeGadget::UI_type::ui_double_spinbox, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto spinbox = qobject_cast<QDoubleSpinBox *>(widget);
if (spinbox == nullptr)
{
@@ -423,11 +424,11 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
bool enabled = ui_item.at("enabled");
bool visible = ui_item.at("visible");
double min = ui_item.at("min");
double max = ui_item.at("max");
double value = ui_item.at("value");
bool enabled = ui_item.enabled();
bool visible = ui_item.visible();
double min = ui_item.range().min();
double max = ui_item.range().max();
double value = ui_item.range().value();
if (enabled != spinbox->isEnabled())
{
@@ -452,7 +453,7 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
spinbox->setValue(value);
}
});
m_process_lookup.insert(UI_enum::ui_hex_spinbox, [=, this](json &ui_item, QWidget *widget) {
m_process_lookup.insert(UI_typeGadget::UI_type::ui_hex_spinbox, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto spinbox = qobject_cast<HexSpinBox *>(widget);
if (spinbox == nullptr)
{
@@ -460,11 +461,11 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
bool enabled = ui_item.at("enabled");
bool visible = ui_item.at("visible");
double min = ui_item.at("min");
double max = ui_item.at("max");
double value = ui_item.at("value");
bool enabled = ui_item.enabled();
bool visible = ui_item.visible();
double min = ui_item.range().min();
double max = ui_item.range().max();
double value = ui_item.range().value();
if (enabled != spinbox->isEnabled())
{
@@ -489,7 +490,7 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
spinbox->setValue((int)value);
}
});
m_process_lookup.insert(UI_enum::ui_tab_widget, [=, this](json &ui_item, QWidget *widget) {
m_process_lookup.insert(UI_typeGadget::UI_type::ui_tab_widget, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto tab_widget = qobject_cast<QTabWidget *>(widget);
if (tab_widget == nullptr)
{
@@ -497,15 +498,15 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
if (tab_widget->count() != ui_item.at("tab_names").size())
if (tab_widget->count() != ui_item.tabWidget().tabNames().size())
{
LOG_ERROR("QTabWidget has not the same amount of tabs as the server");
return;
}
auto tab_names = ui_item.at("tab_names");
bool enabled = ui_item.at("enabled");
bool visible = ui_item.at("visible");
auto tab_names = ui_item.tabWidget().tabNames();
bool enabled = ui_item.enabled();
bool visible = ui_item.visible();
if (tab_widget->isEnabled() != enabled)
{
@@ -519,22 +520,22 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
for (size_t i = 0; i < tab_names.size(); i++)
{
if (tab_widget->tabText(i) != QString::fromStdString(tab_names[i]))
if (tab_widget->tabText(i) != tab_names[i])
{
tab_widget->setTabText(i, QString::fromStdString(tab_names[i]));
tab_widget->setTabText(i, tab_names[i]);
}
if (tab_widget->isVisible() != ui_item.at("tab_visible")[i])
if (tab_widget->isVisible() != ui_item.tabWidget().tabVisible()[i])
{
tab_widget->setTabVisible(i, ui_item.at("tab_visible")[i]);
tab_widget->setTabVisible(i, ui_item.tabWidget().tabVisible()[i]);
}
}
if (tab_widget->currentIndex() != ui_item.at("selected"))
if (tab_widget->currentIndex() != ui_item.tabWidget().selecteTab())
{
tab_widget->setCurrentIndex(ui_item.at("selected"));
tab_widget->setCurrentIndex(ui_item.tabWidget().selecteTab());
}
});
m_process_lookup.insert(UI_enum::ui_stacked_widget, [=, this](json &ui_item, QWidget *widget) {
m_process_lookup.insert(UI_typeGadget::UI_type::ui_stacked_widget, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto stacked_widget = qobject_cast<QStackedWidget *>(widget);
if (stacked_widget == nullptr)
{
@@ -542,14 +543,14 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
if (stacked_widget->count() != ui_item.at("tab_count"))
if (stacked_widget->count() != ui_item.stackedWidget().tabCount())
{
LOG_ERROR("QStackedWidget has not the same amount of tabs as the server");
return;
}
bool enabled = ui_item.at("enabled");
bool visible = ui_item.at("visible");
bool enabled = ui_item.enabled();
bool visible = ui_item.visible();
if (stacked_widget->isEnabled() != enabled)
{
@@ -561,12 +562,12 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
stacked_widget->setVisible(visible);
}
if (stacked_widget->currentIndex() != ui_item.at("current_tab"))
if (stacked_widget->currentIndex() != ui_item.stackedWidget().currentTab())
{
stacked_widget->setCurrentIndex(ui_item.at("current_tab"));
stacked_widget->setCurrentIndex(ui_item.stackedWidget().currentTab());
}
});
m_process_lookup.insert(UI_enum::ui_status_bar, [=, this](json &ui_item, QWidget *widget) {
m_process_lookup.insert(UI_typeGadget::UI_type::ui_status_bar, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto status_bar = qobject_cast<QStatusBar *>(widget);
if (status_bar == nullptr)
{
@@ -574,12 +575,12 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
if (status_bar->currentMessage() != QString::fromStdString(ui_item.at("text")))
if (status_bar->currentMessage() != ui_item.statusBar().message())
{
status_bar->showMessage(QString::fromStdString(ui_item.at("text")), ui_item.at("timeout"));
status_bar->showMessage(ui_item.statusBar().message(), ui_item.statusBar().timeout());
}
});
m_process_lookup.insert(UI_enum::ui_plot, [=, this](json &ui_item, QWidget *widget) {
m_process_lookup.insert(UI_typeGadget::UI_type::ui_plot, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto plot = qobject_cast<Plot_wrapper *>(widget);
if (plot == nullptr)
{
@@ -587,17 +588,17 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
QString text = QString::fromStdString(ui_item.at("text"));
QColor bg_color = QColor(QString::fromStdString(ui_item.at("bg_color")));
QColor color = QColor(QString::fromStdString(ui_item.at("fg_color")));
QString x_label = QString::fromStdString(ui_item.at("x_label"));
QString y_label = QString::fromStdString(ui_item.at("y_label"));
QString text = ui_item.plot().text();
QColor bg_color = QColor(ui_item.plot().color().bgColor());
QColor color = QColor(ui_item.plot().color().fgColor());
QString x_label = ui_item.plot().xLabel();
QString y_label = ui_item.plot().yLabel();
std::vector<double> x_vals = (std::vector<double>)ui_item.at("x_vals");
std::vector<double> y_vals = (std::vector<double>)ui_item.at("y_vals");
QList<double> x_vals = ui_item.plot().xVals();
QList<double> y_vals = ui_item.plot().yVals();
bool enabled = ui_item.at("enabled");
bool visible = ui_item.at("visible");
bool enabled = ui_item.enabled();
bool visible = ui_item.visible();
if (plot->isEnabled() != enabled)
{
@@ -639,7 +640,7 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
plot->setAxisScale(QwtAxis::XBottom, x_vals[0], x_vals[x_vals.size() - 1]);
plot->replot();
});
m_process_lookup.insert(UI_enum::ui_table, [=, this](json &ui_item, QWidget *widget) {
m_process_lookup.insert(UI_typeGadget::UI_type::ui_table, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto table = qobject_cast<QTableWidget *>(widget);
if (table == nullptr)
{
@@ -647,13 +648,13 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
return;
}
size_t row_count = ui_item.at("row_count");
std::vector<std::string> row_labels = (std::vector<std::string>)ui_item.at("row_labels");
size_t column_count = ui_item.at("column_count");
std::vector<std::string> column_labels = (std::vector<std::string>)ui_item.at("column_labels");
std::vector<std::string> table_data = (std::vector<std::string>)ui_item.at("table");
bool enabled = ui_item.at("enabled");
bool visible = ui_item.at("visible");
size_t row_count = ui_item.table().rowCount();
QList<QString> row_labels = ui_item.table().rowLabels();
size_t column_count = ui_item.table().columnCount();
QList<QString> column_labels = ui_item.table().columnLabels();
QList<QString> table_data = ui_item.table().table();
bool enabled = ui_item.enabled();
bool visible = ui_item.visible();
if (table->isEnabled() != enabled)
{
@@ -683,7 +684,7 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
if (table->verticalHeaderItem(i) == nullptr)
table->setVerticalHeaderItem(i, new QTableWidgetItem());
if (row_labels[i] != table->verticalHeaderItem(i)->text())
table->verticalHeaderItem(i)->setText(QString::fromStdString(row_labels[i]));
table->verticalHeaderItem(i)->setText(row_labels[i]);
}
}
if (column_count != 0)
@@ -693,7 +694,7 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
if (table->horizontalHeaderItem(i) == nullptr)
table->setHorizontalHeaderItem(i, new QTableWidgetItem());
if (column_labels[i] != table->horizontalHeaderItem(i)->text())
table->horizontalHeaderItem(i)->setText(QString::fromStdString(column_labels[i]));
table->horizontalHeaderItem(i)->setText(column_labels[i]);
}
}
for (size_t i = 0; i < table_data.size(); i++)
@@ -704,11 +705,11 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
{
table->setItem(row, column, new QTableWidgetItem());
}
table->item(row, column)->setText(QString::fromStdString(table_data[i]));
table->item(row, column)->setText(table_data[i]);
}
table->resizeColumnsToContents();
});
m_process_lookup.insert(UI_enum::ui_can, [=, this](json &ui_item, QWidget *widget) {
m_process_lookup.insert(UI_typeGadget::UI_type::ui_can, [=, this](const UI_item_m &ui_item, QWidget *widget) {
auto can_ui = qobject_cast<Can_Transceive *>(widget);
if (can_ui == nullptr)
{
@@ -717,14 +718,14 @@ UI_base::UI_base(Web_socket_wrapper *web_socket, QWidget *parent)
}
can_ui->clear();
for (auto &send_item : ui_item.at("send_msgs"))
for (auto &send_item : ui_item.can().sendFrames())
{
can_ui->add_send_item(send_item.at("id"), send_item.at("dlc"), send_item.at("payload"));
can_ui->add_send_item(send_item.sid(), send_item.dlc(), send_item.payload());
}
for (auto &recvd_item : ui_item.at("rcvd_msgs"))
for (auto &recvd_item : ui_item.can().recvFrames())
{
can_ui->add_receive_item(recvd_item.at("id"), recvd_item.at("dlc"), recvd_item.at("payload"));
can_ui->add_receive_item(recvd_item.sid(), recvd_item.dlc(), recvd_item.payload());
}
});
}
@@ -746,12 +747,42 @@ void UI_base::showEvent(QShowEvent *event)
LOG_DEBUG("Connecting callbacks");
m_first_load = true;
connect(m_web_socket, &Web_socket_wrapper::on_command_cb, this, [=, this](json &j) { on_cmd_cb(j); });
connect(m_web_socket, &Web_socket_wrapper::on_event_cb, this, [=, this](json &j) { on_event_cb(j); });
connect(m_web_socket, &Web_socket_wrapper::on_closed, this, [=, this] { m_error->open(); });
auto reply = m_remote_ui_client->Command_get_ui_elements(Empty());
connect(reply.get(), &QGrpcCallReply::finished, reply.get(), [this, reply = std::move(reply)](const QGrpcStatus &status) {
if (!status.isOk())
{
LOG_ERROR(QString("Command get ui elements failed: %0").arg(status.message()));
return;
}
auto response = reply->read<UI_items_m>();
if (!response.has_value())
{
qDebug("Command get ui elements deserialization failed");
return;
}
UI_item_parser(response.value());
},
Qt::SingleShotConnection);
m_web_socket->inhibit_events(true);
m_web_socket->send_command(Web_socket_wrapper::Command::get_UI_elements);
m_stream = m_remote_ui_client->SubscribeUIChanges(Empty());
connect(
m_stream.get(), &QGrpcServerStream::finished, this,
[this](const QGrpcStatus &status) {
if (!status.isOk())
m_error->show();
},
Qt::SingleShotConnection);
connect(m_stream.get(), &QGrpcServerStream::messageReceived, this, [this, stream = m_stream.get()] {
auto response = stream->read<UI_items_m>();
if (!response.has_value())
{
qDebug("Client (UnaryCall) deserialization failed");
return;
}
UI_item_parser(response.value());
});
this->m_timer_update->start(m_refresh_rate);
m_open = true;
}
@@ -763,64 +794,30 @@ void UI_base::closeEvent(QCloseEvent *event)
{
LOG_DEBUG("Disconnecting callbacks");
m_timer_update->stop();
disconnect(m_web_socket, nullptr, nullptr, nullptr);
disconnect(m_stream.get(), nullptr, nullptr, nullptr);
m_open = false;
this->parentWidget()->show();
}
}
void UI_base::on_cmd_cb(json &j)
{
auto response = magic_enum::enum_cast<Web_socket_wrapper::Command>(std::string(j.at("type")))
.value_or(Web_socket_wrapper::Command::end);
switch (response)
{
case Web_socket_wrapper::Command::get_UI_elements:
case Web_socket_wrapper::Command::get_UI_element:
UI_item_parser(j);
break;
default:
break;
}
if (m_first_load)
{
m_web_socket->inhibit_events(false);
m_first_load = false;
}
}
void UI_base::on_event_cb(json &j)
{
auto response = magic_enum::enum_cast<Web_socket_wrapper::Event>(std::string(j.at("type")))
.value_or(Web_socket_wrapper::Event::end);
switch (response)
{
case Web_socket_wrapper::Event::ui_changed:
UI_item_parser(j);
break;
default:
break;
}
}
void UI_base::push_ui_item(QWidget *item)
{
m_ui_lookup.emplace_back(item);
setup_ui_item(item, m_ui_lookup.size() - 1);
}
void UI_base::UI_item_parser(json &input)
void UI_base::UI_item_parser(UI_items_m &input)
{
for (auto &ui_item : input.at("UI_items"))
for (auto &ui_item : input.item())
{
auto widget = id_to_ui(ui_item.at("id"));
auto widget = id_to_ui(ui_item.id_proto());
if (widget == nullptr)
{
LOG_WARN(QString("id_to_ui returned null on %0").arg((size_t)ui_item.at("id")));
LOG_WARN(QString("id_to_ui returned null on %0").arg((size_t)ui_item.id_proto()));
return;
}
m_process_lookup[magic_enum::enum_cast<UI_enum>((std::string)ui_item.at("type")).value_or(UI_enum::end)](
m_process_lookup[ui_item.type()](
ui_item, widget);
}
}
@@ -845,8 +842,12 @@ void UI_base::setup_button(QWidget *item, size_t index)
QPushButton *button = qobject_cast<QPushButton *>(item);
if (button == nullptr)
return;
connect(button, &QPushButton::clicked, this,
[=, this] { m_web_socket->send_event(Web_socket_wrapper::Event::clicked, index); });
connect(button, &QPushButton::clicked, this, [=, this] {
auto event = Event_m();
event.setId_proto(index);
event.setClicked(Clicked_m());
(void)m_remote_ui_client->SendEvent(event);
});
}
void UI_base::setup_combobox(QWidget *item, size_t index)
@@ -855,8 +856,12 @@ void UI_base::setup_combobox(QWidget *item, size_t index)
if (combobox == nullptr)
return;
connect(combobox, &QComboBox::activated, this, [=, this] {
m_web_socket->send_event(Web_socket_wrapper::Event::selected, index, (size_t)combobox->currentIndex());
connect(combobox, &QComboBox::activated, this, [=, this](int combo_index) {
auto event = Event_m();
event.setSelected(Selected_m());
event.setId_proto(index);
event.selected().setSelected(combo_index);
(void)m_remote_ui_client->SendEvent(event);
});
}
@@ -866,8 +871,12 @@ void UI_base::setup_checkbox(QWidget *item, size_t index)
if (checkbox == nullptr)
return;
connect(checkbox, &QCheckBox::clicked, this,
[=, this] { m_web_socket->send_event(Web_socket_wrapper::Event::clicked, index); });
connect(checkbox, &QCheckBox::clicked, this, [=, this] {
auto event = Event_m();
event.setId_proto(index);
event.setClicked(Clicked_m());
(void)m_remote_ui_client->SendEvent(event);
});
}
void UI_base::setup_dial(QWidget *item, size_t index)
@@ -891,8 +900,13 @@ void UI_base::setup_slider(QWidget *item, size_t index)
return;
}
connect(slider, &QwtSlider::sliderMoved, this,
[=, this] { m_web_socket->send_event(Web_socket_wrapper::Event::value_changed, index, slider->value()); });
connect(slider, &QwtSlider::sliderMoved, this, [=, this] (double value) {
auto event = Event_m();
event.setId_proto(index);
event.setValueChanged(Value_changed_m());
event.valueChanged().setValue(value);
(void)m_remote_ui_client->SendEvent(event);
});
}
void UI_base::setup_textbox(QWidget *item, size_t index)
@@ -901,8 +915,13 @@ void UI_base::setup_textbox(QWidget *item, size_t index)
if (line_edit == nullptr)
return;
connect(line_edit, &QLineEdit::textEdited, this,
[=, this] { m_web_socket->send_event(Web_socket_wrapper::Event::text_changed, index, line_edit->text()); });
connect(line_edit, &QLineEdit::textEdited, this, [=, this] {
auto event = Event_m();
event.setId_proto(index);
event.setTextChanged(Text_changed_m());
event.textChanged().setText(line_edit->text());
(void)m_remote_ui_client->SendEvent(event);
});
}
void UI_base::setup_spinbox(QWidget *item, size_t index)
@@ -912,7 +931,11 @@ void UI_base::setup_spinbox(QWidget *item, size_t index)
return;
connect(spinbox, &QSpinBox::valueChanged, this, [=, this](int value) {
m_web_socket->send_event(Web_socket_wrapper::Event::value_changed, index, (double)value);
auto event = Event_m();
event.setId_proto(index);
event.setValueChanged(Value_changed_m());
event.valueChanged().setValue(value);
(void)m_remote_ui_client->SendEvent(event);
});
}
@@ -923,7 +946,11 @@ void UI_base::setup_double_spinbox(QWidget *item, size_t index)
return;
connect(spinbox, &QDoubleSpinBox::valueChanged, this, [=, this](double value) {
m_web_socket->send_event(Web_socket_wrapper::Event::value_changed, index, value);
auto event = Event_m();
event.setId_proto(index);
event.setValueChanged(Value_changed_m());
event.valueChanged().setValue(value);
(void)m_remote_ui_client->SendEvent(event);
});
}
@@ -934,7 +961,11 @@ void UI_base::setup_hex_spinbox(QWidget *item, size_t index)
return;
connect(spinbox, &HexSpinBox::valueChanged, this, [=, this](int value) {
m_web_socket->send_event(Web_socket_wrapper::Event::value_changed, index, (double)value);
auto event = Event_m();
event.setId_proto(index);
event.setValueChanged(Value_changed_m());
event.valueChanged().setValue(value);
(void)m_remote_ui_client->SendEvent(event);
});
}
@@ -945,7 +976,11 @@ void UI_base::setup_tab_widget(QWidget *item, size_t index)
return;
connect(tab_widget, &QTabWidget::currentChanged, this, [=, this](int tab_index) {
m_web_socket->send_event(Web_socket_wrapper::Event::selected, index, (size_t)tab_index);
auto event = Event_m();
event.setSelected(Selected_m());
event.setId_proto(index);
event.selected().setSelected(tab_index);
(void)m_remote_ui_client->SendEvent(event);
});
}
@@ -956,9 +991,20 @@ void UI_base::setup_can_ui(QWidget *item, size_t index)
return;
connect(can, &Can_Transceive::send_can_message, this,
[=, this](uint32_t id, uint8_t dlc, std::array<uint8_t, 8> payload) {
m_web_socket->send_event(Web_socket_wrapper::Event::can_send, index, id, dlc, payload);
[=, this](uint32_t id, uint8_t dlc, QByteArray payload) {
auto event = Event_m();
event.setId_proto(index);
event.setCanSend(CAN_send_m());
event.canSend().mutFrame().setSid(id);
event.canSend().mutFrame().setDlc(dlc);
event.canSend().mutFrame().setPayload(payload);
(void)m_remote_ui_client->SendEvent(event);
});
connect(can, &Can_Transceive::can_clear, this,
[=, this] { m_web_socket->send_event(Web_socket_wrapper::Event::clear, index); });
[=, this] {
auto event = Event_m();
event.setId_proto(index);
event.setClear(Clear_m());
(void)m_remote_ui_client->SendEvent(event);
});
}
+14 -22
View File
@@ -1,16 +1,19 @@
#pragma once
#include "ui_enum.hpp"
#include <QMainWindow>
#include <QWidget>
#include <functional>
#include <nlohmann/json.hpp>
#include "messages.qpb.h"
#include "m_ui_items.qpb.h"
#include "messages_client.grpc.qpb.h"
Q_FORWARD_DECLARE_OBJC_CLASS(Web_socket_wrapper);
Q_FORWARD_DECLARE_OBJC_CLASS(QTimer);
Q_FORWARD_DECLARE_OBJC_CLASS(QLabel);
Q_FORWARD_DECLARE_OBJC_CLASS(QMessageBox);
using json = nlohmann::json;
namespace RemoteUiService
{
class Client;
}
#define PUSH_UI_ITEM(item) push_ui_item(ui->item)
@@ -44,11 +47,10 @@ class UI_base : public QMainWindow
* @brief Construct a new ui base object
*
* @param name The name of the simulator
* @param api The weboscket connection to the server API
* @param api The grpc connection to the server API
* @param parent The parent widget
*/
explicit UI_base(Web_socket_wrapper *api, QWidget *parent = nullptr);
void set_name(QString name);
explicit UI_base(RemoteUiService::Client *api, QWidget *parent = nullptr);
/**
* @brief Get the UI element by its ID
*
@@ -56,6 +58,7 @@ class UI_base : public QMainWindow
* @return QWidget* The UI element
*/
QWidget *id_to_ui(size_t id);
void set_name(QString name);
/**
* @brief Get the label associated with a widget
* This function has to be overridden in derived classes if labels are used
@@ -70,18 +73,6 @@ class UI_base : public QMainWindow
}
protected:
/**
* @brief Handle an event callback from the server
*
* @param j The JSON event
*/
void on_event_cb(json &j);
/**
* @brief Handle a command callback from the server
*
* @param j The JSON command
*/
void on_cmd_cb(json &j);
/**
* @brief Push a UI item to the internal list and setup its connections
* The item have to be in the same order as from the server
@@ -94,7 +85,7 @@ class UI_base : public QMainWindow
*
* @param input The JSON input containing UI items
*/
void UI_item_parser(json &input);
void UI_item_parser(UI_items_m &input);
/**
* @brief Setup a generic UI item
*
@@ -198,7 +189,8 @@ class UI_base : public QMainWindow
void log_signal(const char *filename_in, int line_in, const char *funcname_in, int level, QString msg);
private:
Web_socket_wrapper *m_web_socket;
RemoteUiService::Client *m_remote_ui_client;
std::unique_ptr<QGrpcServerStream> m_stream;
QString m_name;
QTimer *m_timer_update;
uint32_t m_refresh_rate;
@@ -206,5 +198,5 @@ class UI_base : public QMainWindow
bool m_open = false;
bool m_first_load = true;
std::vector<QWidget *> m_ui_lookup;
QMap<UI_enum, std::function<void(json &, QWidget *)>> m_process_lookup;
QMap<UI_typeGadget::UI_type, std::function<void(const UI_item_m &, QWidget *)>> m_process_lookup;
};
-240
View File
@@ -1,240 +0,0 @@
#include "web_socket_wrapper.hpp"
#include <QTimer>
#include <QtWebSockets/QWebSocket>
#include <magic_enum/magic_enum.hpp>
#define LOG_SRC_LOC(level, msg) emit log_signal(__FILE__, __LINE__, __FUNCTION__, (int)(level), (msg))
#define LOG_TRACE(msg) LOG_SRC_LOC(Log_level_enum::trace, msg)
#define LOG_DEBUG(msg) LOG_SRC_LOC(Log_level_enum::debug, msg)
#define LOG_INFO(msg) LOG_SRC_LOC(Log_level_enum::info, msg)
#define LOG_WARN(msg) LOG_SRC_LOC(Log_level_enum::warn, msg)
#define LOG_ERROR(msg) LOG_SRC_LOC(Log_level_enum::err, msg)
#define LOG_CRITICAL(msg) LOG_SRC_LOC(Log_level_enum::critical, msg)
Web_socket_wrapper::Web_socket_wrapper(const QUrl &url, QObject *parent)
: QObject(parent), m_web_socket(new QWebSocket("", QWebSocketProtocol::VersionLatest, this)),
m_ping_timer(new QTimer(this)), m_pong_timer(new QTimer(this))
{
connect(m_web_socket, &QWebSocket::connected, this, [=, this] {
m_connected = true;
connect(m_web_socket, &QWebSocket::textMessageReceived, this, &Web_socket_wrapper::m_on_received);
m_ping_timer->start(5000);
emit on_connected();
});
connect(m_web_socket, &QWebSocket::disconnected, this, [=, this] { emit on_closed(); });
connect(m_web_socket, &QWebSocket::errorOccurred, this, [this](QAbstractSocket::SocketError error) {
LOG_ERROR(QString::fromStdString(std::string(magic_enum::enum_name(error))));
});
connect(m_ping_timer, &QTimer::timeout, this, [=, this] {
#ifdef EMSCRIPTEN
if (m_web_socket->state() != QAbstractSocket::ConnectedState)
{
m_web_socket->close();
emit on_closed();
}
m_ping_timer->start(1000);
});
#else
m_web_socket->ping();
m_pong_timer->start(1000);
});
connect(m_web_socket, &QWebSocket::pong, this, [=, this](quint64 elapsedTime) {
if (elapsedTime > 1000)
{
m_web_socket->close();
emit on_closed();
}
m_pong_timer->stop();
m_ping_timer->start(1000);
});
connect(m_pong_timer, &QTimer::timeout, this, [=, this] {
LOG_CRITICAL("Pong timeout");
m_web_socket->close();
emit on_closed();
});
connect(m_web_socket, &QWebSocket::sslErrors,
this, [&](const QList<QSslError> &errors) {
QList<QSslError> exeptions;
for (const QSslError &err : errors) {
switch (err.error()) {
case QSslError::UnableToGetLocalIssuerCertificate:
// case QSslError::UnableToVerifyFirstCertificate:
// case QSslError::SelfSignedCertificate:
// case QSslError::SelfSignedCertificateInChain:
// case QSslError::CertificateUntrusted:
exeptions.append(err);
LOG_WARN(QString("Allowing SSL error: %1 (%2)")
.arg(err.errorString(), err.certificate().isNull()
? "no cert"
: err.certificate().subjectDisplayName()));
break;
default:
LOG_ERROR(QString("Unexpected SSL error (not ignored): %1")
.arg(err.errorString()));
break;
}
}
if (!exeptions.isEmpty()) {
m_web_socket->ignoreSslErrors(exeptions);
}
});
#endif
m_ping_timer->setSingleShot(true);
m_pong_timer->setSingleShot(true);
m_web_socket->setProxy(QNetworkProxy::NoProxy);
m_web_socket->open(url);
}
void Web_socket_wrapper::send_command(Command c, size_t id)
{
json j;
j["command"]["type"] = magic_enum::enum_name(c).data();
switch (c)
{
case Command::get_UI_element:
j["command"]["id"] = id;
m_web_socket->sendTextMessage(QString(j.dump().data()));
break;
case Command::get_UI_elements:
m_web_socket->sendTextMessage(QString(j.dump().data()));
break;
case Command::get_active_simulator_name:
m_web_socket->sendTextMessage(QString(j.dump().data()));
break;
case Command::get_simulators:
m_web_socket->sendTextMessage(QString(j.dump().data()));
break;
default:
break;
}
}
void Web_socket_wrapper::send_command(Command command, QString val)
{
json j;
j["command"]["type"] = magic_enum::enum_name(command).data();
switch (command)
{
case Command::switch_simulator:
j["command"]["name"] = val.toStdString();
m_web_socket->sendTextMessage(QString(j.dump().data()));
break;
default:
break;
}
}
void Web_socket_wrapper::send_event(Event e, size_t id)
{
if (m_inhibit_events)
return;
json j;
j["event"]["type"] = magic_enum::enum_name(e).data();
switch (e)
{
case Event::clicked:
case Event::clear:
j["event"]["id"] = id;
m_web_socket->sendTextMessage(QString(j.dump().data()));
break;
default:
break;
}
}
void Web_socket_wrapper::send_event(Event e, size_t id, size_t val)
{
if (m_inhibit_events)
return;
json j;
j["event"]["type"] = magic_enum::enum_name(e).data();
switch (e)
{
case Event::selected:
j["event"]["id"] = id;
j["event"]["selected"] = val;
m_web_socket->sendTextMessage(QString(j.dump().data()));
break;
default:
break;
}
}
void Web_socket_wrapper::send_event(Event e, size_t id, double val)
{
if (m_inhibit_events)
return;
json j;
j["event"]["type"] = magic_enum::enum_name(e).data();
switch (e)
{
case Event::value_changed:
j["event"]["id"] = id;
j["event"]["value"] = val;
m_web_socket->sendTextMessage(QString(j.dump().data()));
break;
default:
break;
}
}
void Web_socket_wrapper::send_event(Event e, size_t id, QString val)
{
if (m_inhibit_events)
return;
json j;
j["event"]["type"] = magic_enum::enum_name(e).data();
switch (e)
{
case Event::text_changed:
j["event"]["id"] = id;
j["event"]["text"] = val.toStdString();
m_web_socket->sendTextMessage(QString(j.dump().data()));
break;
default:
break;
}
}
void Web_socket_wrapper::send_event(Event e, size_t id, uint32_t sid, uint8_t dlc, std::array<uint8_t, 8> payload)
{
if (m_inhibit_events)
return;
json j;
j["event"]["type"] = magic_enum::enum_name(e).data();
switch (e)
{
case Event::can_send:
j["event"]["id"] = id;
j["event"]["sid"] = sid;
j["event"]["dlc"] = dlc;
j["event"]["payload"] = payload;
m_web_socket->sendTextMessage(QString(j.dump().data()));
break;
default:
break;
}
}
void Web_socket_wrapper::m_on_received(QString message)
{
json j = json::parse(message.toStdString());
if (j.contains("response"))
{
emit on_command_cb(j.at("response"));
return;
}
if (j.contains("event"))
{
emit on_event_cb(j.at("event"));
return;
}
}
void Web_socket_wrapper::inhibit_events(bool inhibit)
{
m_inhibit_events = inhibit;
}
-171
View File
@@ -1,171 +0,0 @@
#pragma once
#include <QObject>
#include <nlohmann/json.hpp>
Q_FORWARD_DECLARE_OBJC_CLASS(QWebSocket);
Q_FORWARD_DECLARE_OBJC_CLASS(QTimer);
using json = nlohmann::json;
/**
* @brief Class wrapping a WebSocket connection
*
*/
class Web_socket_wrapper : public QObject
{
Q_OBJECT
public:
/**
* @brief Enumeration of commands
*/
enum class Command
{
get_UI_element,
get_UI_elements,
switch_simulator,
get_active_simulator_name,
get_simulators,
end,
begin = 0
};
enum class Log_level_enum : int
{
trace,
debug,
info,
warn,
err,
critical,
off,
n_levels
};
/**
* @brief Enumeration of events
*
*/
enum class Event
{
clicked,
value_changed,
text_changed,
selected,
can_send,
clear,
ui_changed,
end,
begin = 0
};
public:
/**
* @brief Construct a new Web_socket_wrapper object
*
* @param url The WebSocket URL to connect to
* @param parent The parent QObject
*/
explicit Web_socket_wrapper(const QUrl &url, QObject *parent = nullptr);
/**
* @brief Send a command to the server
*
* @param c The command to send
* @param id The ID associated with the command (if applicable)
*/
void send_command(Command c, size_t id = 0);
/**
* @brief Send a command to the server with a string value
*
* @param c The command to send
* @param val The string value associated with the command
*/
void send_command(Command c, QString val);
/**
* @brief Send an event to the server
*
* @param e The event to send
* @param id The ID associated with the event
*/
void send_event(Event e, size_t id);
/**
* @brief Send an event to the server with a size_t value
*
* @param e The event to send
* @param id The ID associated with the event
* @param val The size_t value associated with the event
*/
void send_event(Event e, size_t id, size_t val);
/**
* @brief Send an event to the server with a double value
*
* @param e The event to send
* @param id The ID associated with the event
* @param val The double value associated with the event
*/
void send_event(Event e, size_t id, double val);
/**
* @brief Send an event to the server with a string value
*
* @param e The event to send
* @param id The ID associated with the event
* @param val The string value associated with the event
*/
void send_event(Event e, size_t id, QString val);
/**
* @brief Send a CAN event to the server
*
* @param e The event to send
* @param id The ID associated with the event
* @param sid The CAN standard identifier
* @param dlc The CAN data length code
* @param payload The CAN data payload
*/
void send_event(Event e, size_t id, uint32_t sid, uint8_t dlc, std::array<uint8_t, 8> payload);
/**
* @brief Inhibit or allow sending events to the server
*
* @param inhibit True to inhibit events, false to allow
*/
void inhibit_events(bool inhibit);
signals:
/**
* @brief Signal emitted when the WebSocket is connected
*
*/
void on_connected();
/**
* @brief Signal emitted when the WebSocket is closed
*
*/
void on_closed();
/**
* @brief Signal emitted when a command is received from the server
*
* @param data The JSON command data
*/
void on_command_cb(json &data);
/**
* @brief Signal emitted when an event is received from the server
*
* @param data The JSON event data
*/
void on_event_cb(json &data);
void log_signal(const char *filename_in, int line_in, const char *funcname_in, int level, QString msg);
private Q_SLOTS:
/**
* @brief Internal slot for handling WebSocket disconnection
*
*/
void m_on_received(QString message);
private:
bool m_connected = false;
bool m_inhibit_events = false;
QWebSocket *m_web_socket;
QTimer *m_ping_timer;
QTimer *m_pong_timer;
};
+43
View File
@@ -0,0 +1,43 @@
find_package(Qt6 REQUIRED COMPONENTS Protobuf Grpc)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_library(proto-ui STATIC)
set_target_properties(
proto-ui
PROPERTIES
AUTOMOC ON
POSITION_INDEPENDENT_CODE ON
)
qt_add_protobuf(proto-ui
PROTO_FILES
${CMAKE_CURRENT_LIST_DIR}/m_ui_items.proto
${CMAKE_CURRENT_LIST_DIR}/messages.proto
)
target_link_libraries(proto-ui PUBLIC Qt6::Protobuf)
add_library(proto-ui-client STATIC)
set_target_properties(
proto-ui-client
PROPERTIES
AUTOMOC ON
POSITION_INDEPENDENT_CODE ON
)
qt_add_grpc(proto-ui-client CLIENT
PROTO_FILES
${CMAKE_CURRENT_LIST_DIR}/messages.proto
)
target_link_libraries(proto-ui-client PUBLIC Qt6::Protobuf Qt6::Grpc proto-ui)
# add_library(proto-ui-server STATIC)
# set_target_properties(
# proto-ui-server
# PROPERTIES
# AUTOMOC ON
# POSITION_INDEPENDENT_CODE ON
# )
# qt_add_grpc(proto-ui-server SERVER
# PROTO_FILES
# ${CMAKE_CURRENT_LIST_DIR}/messages.proto
# )
# target_link_libraries(proto-ui-server PUBLIC Qt6::Protobuf Qt6::Grpc proto-ui)
+131
View File
@@ -0,0 +1,131 @@
syntax = "proto3";
enum UI_type {
undef = 0;
ui_button = 1;
ui_can = 2;
ui_checkbox = 3;
ui_combobox = 4;
ui_dial = 5;
ui_double_spinbox = 6;
ui_hex_spinbox = 7;
ui_label = 8;
ui_led = 9;
ui_plot = 10;
ui_slider = 11;
ui_spinbox = 12;
ui_stacked_widget = 13;
ui_status_bar = 14;
ui_tab_widget = 15;
ui_table = 16;
ui_textbox = 17;
ui_thermo = 18;
}
message CAN_Frame_m {
uint32 sid = 1;
int64 dlc = 2;
bytes payload = 3;
}
message UI_color {
uint32 fg_color = 1;
uint32 bg_color = 2;
}
message UI_label_m {
UI_color color = 1;
string text = 2;
}
message UI_can_m {
UI_color color = 1;
repeated CAN_Frame_m send_frames = 2;
repeated CAN_Frame_m recv_frames = 3;
}
message UI_checkbox_m {
UI_color color = 1;
string text = 2;
bool checked = 3;
}
message UI_combobox_m {
int64 selected = 1;
repeated string options = 2;
}
message UI_range_m {
double min = 1;
double max = 2;
double value = 3;
string unit = 4;
string text = 5;
}
message UI_spinbox_m {
double min = 1;
double max = 2;
double value = 3;
}
message UI_plot_m {
UI_color color = 1;
string text = 2;
string x_label = 3;
string y_label = 4;
repeated double x_vals = 5;
repeated double y_vals = 6;
}
message UI_stacked_widget_m {
int64 tab_count = 1;
int64 current_tab = 2;
}
message UI_tab_widget_m {
int64 selecte_tab = 1;
repeated string tab_names = 2;
repeated bool tab_visible = 3;
}
message UI_status_bar_m {
uint64 timeout = 1;
string message = 2;
}
message UI_table_m {
int64 row_count = 1;
int64 column_count = 2;
repeated string row_labels = 3;
repeated string column_labels = 4;
repeated string table = 5;
}
message UI_textbox_m {
UI_color color = 1;
string text = 2;
string hint = 3;
}
message UI_item_m {
uint64 id = 1;
UI_type type = 2;
bool enabled = 3;
bool visible = 4;
oneof kind {
UI_label_m label = 5;
UI_can_m can = 6;
UI_checkbox_m checkbox = 7;
UI_combobox_m combobox = 8;
UI_range_m range = 9;
UI_spinbox_m spinbox = 10;
UI_plot_m plot = 11;
UI_stacked_widget_m stacked_widget = 12;
UI_tab_widget_m tab_widget = 13;
UI_status_bar_m status_bar = 14;
UI_table_m table = 15;
UI_textbox_m textbox = 16;
}
}
+50
View File
@@ -0,0 +1,50 @@
syntax = "proto3";
import "m_ui_items.proto";
message Empty {}
message UI_id_m { uint32 id = 1; }
message UI_items_m { repeated UI_item_m item = 1; }
message Simulator_m { string simuator = 1;}
message Simulators_m { repeated string simulator = 1; }
message Clicked_m {}
message Value_changed_m { double value = 1; }
message Text_changed_m { string text = 1; }
message Selected_m { uint32 selected = 1; }
message CAN_send_m { CAN_Frame_m frame = 1; }
message Clear_m {}
message Event_m {
uint32 id = 1;
oneof kind {
Clicked_m clicked = 2;
Value_changed_m value_changed = 3;
Text_changed_m text_changed = 4;
Selected_m selected = 5;
CAN_send_m can_send = 6;
Clear_m clear = 7;
}
}
service RemoteUiService {
// Commands
rpc Command_get_ui_element (UI_id_m) returns (UI_items_m);
rpc Command_get_ui_elements (Empty) returns (UI_items_m);
rpc Command_switch_simulator (Simulator_m) returns (Empty);
rpc Command_get_active_simulator (Empty) returns (Simulator_m);
rpc Command_get_simulators (Empty) returns (Simulators_m);
// Events
rpc SendEvent (Event_m) returns (Empty);
// Broadcasting
rpc SubscribeUIChanges (Empty) returns (stream UI_items_m);
}
+1
View File
@@ -57,6 +57,7 @@ target_sources(server_common
target_link_libraries(server_common
PUBLIC
UI
proto-ui
spdlog
cpp_templates
${GPIOD_LIB}
+90 -95
View File
@@ -3,122 +3,122 @@
#include <magic_enum/magic_enum.hpp>
#include <spdlog/spdlog.h>
QString Simulators::message_parser(QString message)
// TODO: Fix parsing messages
QByteArray Simulators::message_parser(QByteArray message)
{
json j = json::parse(message.toStdString());
if (j.contains("command"))
Event_m event_m;
bool event = m_serializer.deserialize(&event_m, message);
// if (j.contains("command"))
// {
// return QString::fromStdString(command_parser(j["command"]).dump());
// }
/*else*/ if (event)
{
return QString::fromStdString(command_parser(j["command"]).dump());
event_handler(event_m);
}
else if (j.contains("event"))
{
event_handler(j["event"]);
}
return "{}";
return QByteArray();
}
json Simulators::command_parser(json command)
{
json j = "{}"_json;
try
{
std::string type = command.at("type");
Command cmd = magic_enum::enum_cast<Command>(type).value_or(Command::end);
switch (cmd)
{
case Command::get_UI_element:
SPDLOG_INFO("Command {}: {}", type, (size_t)command.at("id"));
if (is_not_active())
{
SPDLOG_ERROR("Command got called but there is no active simulator");
return j;
}
j["response"]["type"] = type;
j["response"]["UI_item"] =
invoke_active_simulator()->get_UI_item(command.at("id"))->to_json(command.at("id"));
break;
case Command::get_UI_elements:
SPDLOG_INFO("Command {}", type);
if (is_not_active())
{
SPDLOG_ERROR("Command got called but there is no active simulator");
return j;
}
j["response"]["type"] = type;
j["response"]["UI_items"] = invoke_active_simulator()->get_UI_items()["UI_items"];
break;
case Command::switch_simulator:
SPDLOG_INFO("Command {} to {}", type, std::string(command.at("name")));
switch_simulator(command.at("name"));
j["response"]["type"] = type;
break;
case Command::get_active_simulator_name:
SPDLOG_INFO("Command {}", type);
j["response"]["type"] = type;
j["response"]["name"] = active_simulator_name();
break;
case Command::get_simulators:
SPDLOG_INFO("Command {}", type);
j["response"]["type"] = type;
j["response"]["simulators"] = list_simulators();
break;
default:
break;
}
}
catch (const json::exception &e)
{
SPDLOG_ERROR("{} {}", __FUNCTION__, e.what());
}
// QByteArray Simulators::command_parser(json command)
// {
// json j = "{}"_json;
// try
// {
// std::string type = command.at("type");
// Command cmd = magic_enum::enum_cast<Command>(type).value_or(Command::end);
// switch (cmd)
// {
// case Command::get_UI_element:
// SPDLOG_INFO("Command {}: {}", type, (size_t)command.at("id"));
// if (is_not_active())
// {
// SPDLOG_ERROR("Command got called but there is no active simulator");
// return j;
// }
// j["response"]["type"] = type;
// j["response"]["UI_item"] =
// invoke_active_simulator()->get_UI_item(command.at("id"))->to_json(command.at("id"));
// break;
// case Command::get_UI_elements:
// SPDLOG_INFO("Command {}", type);
// if (is_not_active())
// {
// SPDLOG_ERROR("Command got called but there is no active simulator");
// return j;
// }
// j["response"]["type"] = type;
// j["response"]["UI_items"] = invoke_active_simulator()->get_UI_items()["UI_items"];
// break;
// case Command::switch_simulator:
// SPDLOG_INFO("Command {} to {}", type, std::string(command.at("name")));
// switch_simulator(command.at("name"));
// j["response"]["type"] = type;
// break;
// case Command::get_active_simulator_name:
// SPDLOG_INFO("Command {}", type);
// j["response"]["type"] = type;
// j["response"]["name"] = active_simulator_name();
// break;
// case Command::get_simulators:
// SPDLOG_INFO("Command {}", type);
// j["response"]["type"] = type;
// j["response"]["simulators"] = list_simulators();
// break;
// default:
// break;
// }
// }
// catch (const json::exception &e)
// {
// SPDLOG_ERROR("{} {}", __FUNCTION__, e.what());
// }
return j;
}
// return j;
// }
void Simulators::event_handler(json event)
void Simulators::event_handler(Event_m event)
{
try
{
std::string type = event.at("type");
Event e = magic_enum::enum_cast<Event>(type).value_or(Event::end);
if (invoke_active_simulator() == nullptr)
{
SPDLOG_ERROR("Event got called but there is no active simulator");
return;
}
switch (e)
QString type; // = QString::fromStdString(magic_enum::enum_cast<Event_m::KindFields>(event.kindField()).value_or(Event_m::KindFields::UninitializedField));
switch (event.kindField())
{
case Event::clicked: {
SPDLOG_DEBUG("Event {}: {}", type, (size_t)event.at("id"));
invoke_active_simulator()->get_UI_item(event.at("id"))->click();
case Event_m::KindFields::Clicked: {
SPDLOG_DEBUG("Event {}: {}", type, (size_t)event.id_proto());
invoke_active_simulator()->get_UI_item(event.id_proto())->click();
break;
}
case Event::value_changed: {
SPDLOG_DEBUG("Event {}: {} {}", type, (size_t)event.at("id"), (double)(event["value"]));
invoke_active_simulator()->get_UI_item(event.at("id"))->set_value((double)event.at("value"));
case Event_m::KindFields::ValueChanged: {
SPDLOG_DEBUG("Event {}: {} {}", type, event.id_proto(), event.valueChanged().value());
invoke_active_simulator()->get_UI_item(event.id_proto())->set_value(event.valueChanged().value());
break;
}
case Event::text_changed: {
SPDLOG_DEBUG("Event {}: {} {}", type, (size_t)event.at("id"), std::string(event.at("text")));
invoke_active_simulator()->get_UI_item(event.at("id"))->set_text(std::string(event.at("text")));
case Event_m::KindFields::TextChanged: {
SPDLOG_DEBUG("Event {}: {} {}", type, event.id_proto(), event.textChanged().text());
invoke_active_simulator()->get_UI_item(event.id_proto())->set_text(event.textChanged().text());
break;
}
case Event::selected: {
SPDLOG_DEBUG("Event {}: {} {}", type, (size_t)event.at("id"), std::to_string((size_t)event.at("selected")));
invoke_active_simulator()->get_UI_item(event.at("id"))->set_selected(event.at("selected"));
case Event_m::KindFields::Selected: {
SPDLOG_DEBUG("Event {}: {} {}", type, event.id_proto(), std::to_string(event.selected().selected()));
invoke_active_simulator()->get_UI_item(event.id_proto())->set_selected(event.selected().selected());
break;
}
case Event::can_send: {
SPDLOG_DEBUG("Event {}: {}", type, (size_t)event.at("id"));
case Event_m::KindFields::CanSend: {
SPDLOG_DEBUG("Event {}: {}", type, event.id_proto());
invoke_active_simulator()
->get_UI_item(event.at("id"))
->can_send((uint32_t)event.at("sid"), (uint8_t)event.at("dlc"),
(std::array<uint8_t, 8>)event.at("payload"));
->get_UI_item(event.id_proto())
->can_send(event.canSend().frame().sid(), event.canSend().frame().dlc(),
event.canSend().frame().payload());
break;
}
case Event::clear: {
SPDLOG_DEBUG("Event {}: {}", type, (size_t)event.at("id"));
invoke_active_simulator()->get_UI_item(event.at("id"))->clear();
case Event_m::KindFields::Clear: {
SPDLOG_DEBUG("Event {}: {}", type, event.id_proto());
invoke_active_simulator()->get_UI_item(event.id_proto())->clear();
break;
}
default: {
@@ -126,8 +126,3 @@ void Simulators::event_handler(json event)
}
}
}
catch (const json::exception &e)
{
SPDLOG_ERROR("{} {}", __FUNCTION__, e.what());
}
}
+6 -6
View File
@@ -2,7 +2,7 @@
#include "simulator_base.hpp"
#include "ui_item.hpp"
Simulator_base::Simulator_base(std::string name, Communication *com, std::chrono::milliseconds interval,
Simulator_base::Simulator_base(QString name, Communication *com, std::chrono::milliseconds interval,
QObject *parent)
: QObject(parent), m_name(name), m_timer(new QTimer(this)), m_interval(interval), m_com(com)
{
@@ -10,7 +10,7 @@ Simulator_base::Simulator_base(std::string name, Communication *com, std::chrono
m_UI_items.reserve(50);
}
std::string Simulator_base::name() const
QString Simulator_base::name() const
{
// Get the name of the simulator
return m_name;
@@ -20,17 +20,17 @@ void Simulator_base::push_ui_item(UI_item *item)
{
// Add a UI item to the simulator
connect(item, &UI_item::ui_changed, this, [this] { emit sim_changed(); });
item->set_id(m_UI_items.size());
m_UI_items.push_back(item);
}
json Simulator_base::get_UI_items() const
QList<UI_item_m> Simulator_base::get_UI_items() const
{
// Get the UI items
json items;
items["name"] = m_name;
QList<UI_item_m> items;
for (size_t i = 0; i < m_UI_items.size(); i++)
{
items["UI_items"].push_back(m_UI_items[i]->to_json(i));
items.push_back(m_UI_items[i]->to_proto());
}
return items;
+10 -22
View File
@@ -7,11 +7,8 @@
#ifndef INTERNAL
#include "ui.hpp"
#else
#include <nlohmann/json.hpp>
using json = nlohmann::json;
Q_FORWARD_DECLARE_OBJC_CLASS(UI_item);
Q_FORWARD_DECLARE_OBJC_CLASS(UI_item_m);
#endif
#define PUSH_UI_ITEM(item) push_ui_item(&item)
@@ -75,15 +72,15 @@ class Simulator_base : public QObject
* @param interval The interval of the timer (default is 100ms)
* @param parent The parent QObject
*/
Simulator_base(std::string name, Communication *comms,
Simulator_base(QString name, Communication *comms,
std::chrono::milliseconds interval = std::chrono::milliseconds(100), QObject *parent = nullptr);
/**
* @brief Returns the name of the simulator
*
* @return std::string The name of the simulator
* @return QString The name of the simulator
*/
std::string name() const;
QString name() const;
/**
* @brief This function adds a UI item to the simulator
@@ -98,7 +95,7 @@ class Simulator_base : public QObject
*
* @return json The UI items in json format
*/
json get_UI_items() const;
QList<UI_item_m> get_UI_items() const;
/**
* @brief Get the UI item object by id
@@ -112,20 +109,11 @@ class Simulator_base : public QObject
* @brief Get the id of a UI item by pointer
*
* @param ptr A pointer to the UI item
* @return size_t The id of the UI item, or -1 if not found
* @return qsizetype The id of the UI item, or -1 if not found
*/
size_t ptr_to_id(UI_item *ptr) const
qsizetype ptr_to_id(UI_item *ptr) const
{
size_t id = 0;
while (id < m_UI_items.size())
{
if (m_UI_items[id] == ptr)
{
return id;
}
id++;
}
return (size_t)-1;
return m_UI_items.indexOf(ptr);
}
/**
@@ -196,12 +184,12 @@ class Simulator_base : public QObject
* @brief The name of the simulator
*
*/
std::string m_name;
QString m_name;
/**
* @brief The UI items of the simulator
*
*/
std::vector<UI_item *> m_UI_items;
QList<UI_item *> m_UI_items;
/**
* @brief The timer for the simulator
*
+41 -50
View File
@@ -7,7 +7,6 @@
#include <QDirIterator>
#include <QLibrary>
#include <QThread>
#include <unordered_set>
typedef Simulator_base *(*Get_Sim)(Communication *, QObject *);
@@ -71,17 +70,17 @@ Simulators::Simulators(uint16_t port, QStringList can_devs, QStringList uart_dev
lib.unload();
continue;
}
m_simulators.insert(std::make_pair(widget->name(), widget));
m_simulators.insert(widget->name(), widget);
}
// Insert Debug sims here
// INSERT_SIMULATOR(TEST_SIM);
connect(m_server, &Websocket::on_message, this, [this](QWebSocket *conn, QString message) {
QString response = message_parser(message);
if (response == "{}")
connect(m_server, &Websocket::on_binary_message, this, [this](QWebSocket *conn, QByteArray message) {
QByteArray response = message_parser(message);
if (response.isEmpty())
return;
m_server->send(conn, response);
m_server->send_binary(conn, response);
});
}
@@ -89,7 +88,7 @@ Simulators::~Simulators()
{
}
std::string Simulators::active_simulator_name() const
QString Simulators::active_simulator_name() const
{
return this->m_current_simulator;
}
@@ -101,14 +100,14 @@ void Simulators::start()
SPDLOG_WARN("No simulators found");
return;
}
if (this->m_current_simulator.empty())
if (this->m_current_simulator.isEmpty())
{
SPDLOG_WARN("No active simulator");
return;
}
m_before = this->m_simulators.at(m_current_simulator)->get_UI_items();
this->m_simulators.at(m_current_simulator)->start();
m_before = this->m_simulators.value(m_current_simulator)->get_UI_items();
this->m_simulators.value(m_current_simulator)->start();
}
void Simulators::stop()
@@ -118,16 +117,16 @@ void Simulators::stop()
SPDLOG_WARN("No simulators found");
return;
}
if (this->m_current_simulator.empty())
if (this->m_current_simulator.isEmpty())
{
SPDLOG_WARN("No active simulator");
return;
}
this->m_simulators.at(m_current_simulator)->stop();
this->m_simulators.value(m_current_simulator)->stop();
}
void Simulators::switch_simulator(std::string name)
void Simulators::switch_simulator(QString name)
{
if (this->m_simulators.empty())
{
@@ -136,29 +135,31 @@ void Simulators::switch_simulator(std::string name)
}
if (this->m_simulators.find(name) == this->m_simulators.end())
{
SPDLOG_WARN("Simulator {} not found", name);
SPDLOG_WARN("Simulator {} not found", name.toStdString());
return;
}
if (!this->m_current_simulator.empty())
if (!this->m_current_simulator.isEmpty())
{
SPDLOG_INFO("Stopping current simulator {} and switching to {}", m_current_simulator, name);
this->m_simulators.at(m_current_simulator)->stop();
disconnect(m_simulators.at(m_current_simulator).get());
SPDLOG_INFO("Stopping current simulator {} and switching to {}", m_current_simulator.toStdString(), name.toStdString());
this->m_simulators.value(m_current_simulator)->stop();
disconnect(m_simulators.value(m_current_simulator));
}
this->m_current_simulator = name;
connect(
m_simulators.at(m_current_simulator).get(), &Simulator_base::sim_changed, this,
m_simulators.value(m_current_simulator), &Simulator_base::sim_changed, this,
[this] {
auto json = changed_UI_items();
if (!json.empty())
auto changed = changed_UI_items();
UI_items_m items;
items.setItem(changed);
if (!changed.isEmpty())
{
m_server->broadcast(QString::fromStdString(json.dump()));
m_server->broadcast_binary(m_serializer.serialize(&items));
}
},
Qt::QueuedConnection);
connect(m_simulators.at(m_current_simulator).get(), &Simulator_base::log_signal, this,
connect(m_simulators.value(m_current_simulator), &Simulator_base::log_signal, this,
[](const char *filename_in, int line_in, const char *funcname_in, int level, QString msg) {
if (spdlog::default_logger_raw()->should_log((spdlog::level::level_enum)level))
spdlog::default_logger_raw()->log(spdlog::source_loc{filename_in, line_in, funcname_in},
@@ -167,19 +168,14 @@ void Simulators::switch_simulator(std::string name)
this->start();
}
std::vector<std::string> Simulators::list_simulators() const
QList<QString> Simulators::list_simulators() const
{
std::vector<std::string> names;
for (const auto &simulator : this->m_simulators)
{
names.push_back(simulator.first);
}
return names;
return this->m_simulators.keys();
}
bool Simulators::is_not_active() const
{
return this->m_current_simulator.empty();
return this->m_current_simulator.isEmpty();
}
Simulator_base *Simulators::invoke_active_simulator()
@@ -189,45 +185,40 @@ Simulator_base *Simulators::invoke_active_simulator()
{
return nullptr;
}
if (this->m_current_simulator.empty())
if (this->m_current_simulator.isEmpty())
{
return nullptr;
}
m_before = this->m_simulators.at(m_current_simulator)->get_UI_items();
m_before = this->m_simulators.value(m_current_simulator)->get_UI_items();
return this->m_simulators.at(m_current_simulator).get();
return this->m_simulators.value(m_current_simulator);
}
json Simulators::changed_UI_items()
QList<UI_item_m> Simulators::changed_UI_items()
{
std::lock_guard<std::mutex> lock(m_mutex);
QList<UI_item_m> ret;
if (this->m_simulators.empty() || this->m_current_simulator.empty())
return "{}"_json;
if (this->m_simulators.empty() || this->m_current_simulator.isEmpty())
return ret;
json after = this->m_simulators.at(m_current_simulator)->get_UI_items();
auto after = this->m_simulators.value(m_current_simulator)->get_UI_items();
// Fast path: nothing at all changed
if (after == m_before)
return "{}"_json;
return ret;
json changed;
changed["event"]["type"] = "ui_changed";
const auto &ui_items = after["UI_items"];
const auto &prev_ui_items = m_before["UI_items"]; // may be null on first call
const size_t count = ui_items.size();
for (size_t i = 0; i < count; ++i)
const qsizetype count = after.size();
for (qsizetype i = 0; i < count; ++i)
{
// If item is new or any field changed -> send full current item
if (i >= prev_ui_items.size() || ui_items[i] != prev_ui_items[i])
if (i >= m_before.size() || after[i] != m_before[i])
{
changed["event"]["UI_items"].push_back(ui_items[i]);
ret.push_back(after[i]);
}
}
m_before = std::move(after);
return changed;
return ret;
}
+17 -16
View File
@@ -1,9 +1,10 @@
#pragma once
#include <QObject>
#include <map>
#include <QMap>
#include <memory>
#include <mutex>
#include <nlohmann/json.hpp>
#include <QProtobufSerializer>
#include <messages.qpb.h>
#define INSERT_SIMULATOR(type) \
m_simulators.insert(std::make_pair(type(&m_com).name(), std::make_unique<type>(&m_com, this)));
@@ -14,8 +15,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(CAN_Wrapper);
Q_FORWARD_DECLARE_OBJC_CLASS(QSerialPort);
Q_FORWARD_DECLARE_OBJC_CLASS(Simulator_base);
Q_FORWARD_DECLARE_OBJC_CLASS(Communication);
using json = nlohmann::json;
Q_FORWARD_DECLARE_OBJC_CLASS(UI_item_m);
/**
* @brief Class managing all simulators
@@ -75,9 +75,9 @@ class Simulators : public QObject
/**
* @brief Get the name of the active simulator
*
* @return std::string The name of the active simulator
* @return QString The name of the active simulator
*/
std::string active_simulator_name() const;
QString active_simulator_name() const;
/**
* @brief Start the active simulator
*
@@ -93,13 +93,13 @@ class Simulators : public QObject
*
* @param name The name of the simulator to switch to
*/
void switch_simulator(std::string name);
void switch_simulator(QString name);
/**
* @brief List all available simulators
*
* @return std::vector<std::string> A list of simulator names
* @return std::vector<QString> A list of simulator names
*/
std::vector<std::string> list_simulators() const;
QList<QString> list_simulators() const;
/**
* @brief Check if no simulator is active
*
@@ -120,7 +120,7 @@ class Simulators : public QObject
*
* @return json The changed UI items
*/
json changed_UI_items();
QList<UI_item_m> changed_UI_items();
// Functions in message_parser.cpp
/**
@@ -129,27 +129,28 @@ class Simulators : public QObject
* @param message The message to parse
* @return QString The parsed message
*/
QString message_parser(QString message);
QByteArray message_parser(QByteArray message);
/**
* @brief Parse a command in json format
*
* @param command The command to parse
* @return json The parsed command
*/
json command_parser(json command);
//json command_parser(json command);
/**
* @brief Handle an event in json format
*
* @param event The event to handle
*/
void event_handler(json event);
void event_handler(Event_m event);
private:
QThread *m_server_thread;
Websocket *m_server;
Communication *m_com;
std::map<std::string, std::unique_ptr<Simulator_base>> m_simulators;
std::string m_current_simulator = "";
QMap<QString, Simulator_base*> m_simulators;
QString m_current_simulator = "";
std::mutex m_mutex;
json m_before;
QList<UI_item_m> m_before;
QProtobufSerializer m_serializer;
};
+6 -6
View File
@@ -5,10 +5,10 @@ EXPORT_SIM(Test_Sim);
Test_Sim::Test_Sim(Communication *com, QObject *parent)
: Simulator_base("Test Sim", com, std::chrono::milliseconds(1000), parent),
m_button("Off", Color::White, Color::Red),
m_combobox(Color::White, Color::Black, {"Option 1", "Option 2", "Option 3"}, 0),
m_combobox({"Option 1", "Option 2", "Option 3"}, 0),
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_slider("Slider", 0, 100, 0), m_dial("Dial", 0, 100, 0),
m_thermo("Thermo", "%", 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_spinbox(0, 255, 0), m_double_spinbox(0, 255, 0), m_hex_spinbox(0, 255, 0),
m_tab_widget({"Tab 1", "Tab 2", "Tab 3"}, 0), m_stacked_widget(3, 0), m_status_bar()
@@ -39,7 +39,7 @@ Test_Sim::Test_Sim(Communication *com, QObject *parent)
for (size_t i = 0; i < m_table.capacity(); i++)
{
m_table.insert_item(i / 4, i % 4, QString("%0 %1").arg(i / 4).arg(i % 4).toStdString());
m_table.insert_item(i / 4, i % 4, QString("%0 %1").arg(i / 4).arg(i % 4));
}
QObject::connect(&m_button, &UI_button::clicked, this, [=, this] { button_clicked(&m_button); });
@@ -87,14 +87,14 @@ void Test_Sim::slider_changed(UI_slider *id, double value)
if (id == &m_slider)
{
LOG_INFO(QString("Test slider changed to %0").arg(value));
m_label.set_text(std::to_string(value));
m_label.set_text(QString::number(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);
m_status_bar.show_message("Test slider changed to " + std::to_string(value));
m_status_bar.show_message("Test slider changed to " + QString::number(value));
return;
}
}
+23 -3
View File
@@ -60,7 +60,15 @@ Websocket::~Websocket()
qDeleteAll(m_clients.begin(), m_clients.end());
}
void Websocket::broadcast(QString message)
void Websocket::broadcast_binary(QByteArray message)
{
foreach (QWebSocket *conn, m_clients)
{
conn->sendBinaryMessage(message);
}
}
void Websocket::broadcast_text(QString message)
{
foreach (QWebSocket *conn, m_clients)
{
@@ -68,7 +76,12 @@ void Websocket::broadcast(QString message)
}
}
void Websocket::send(QWebSocket *conn, QString message)
void Websocket::send_binary(QWebSocket *conn, QByteArray message)
{
conn->sendBinaryMessage(message);
}
void Websocket::send_text(QWebSocket *conn, QString message)
{
conn->sendTextMessage(message);
}
@@ -77,16 +90,23 @@ void Websocket::onNewConnection()
{
QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
connect(pSocket, &QWebSocket::binaryMessageReceived, this, &Websocket::processBinaryMessage);
connect(pSocket, &QWebSocket::textMessageReceived, this, &Websocket::processTextMessage);
connect(pSocket, &QWebSocket::disconnected, this, &Websocket::socketDisconnected);
m_clients << pSocket;
}
void Websocket::processBinaryMessage(QByteArray message)
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
emit on_binary_message(pClient, message);
}
void Websocket::processTextMessage(QString message)
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
emit on_message(pClient, message);
emit on_text_message(pClient, message);
}
void Websocket::socketDisconnected()
+7 -3
View File
@@ -41,14 +41,16 @@ class Websocket : public QObject
*
* @param message The message to send
*/
void broadcast(QString message);
void broadcast_binary(QByteArray message);
void broadcast_text(QString message);
/**
* @brief Send a message to a specific client
*
* @param conn The client connection
* @param message The message to send
*/
void send(QWebSocket *conn, QString message);
void send_binary(QWebSocket *conn, QByteArray message);
void send_text(QWebSocket *conn, QString message);
signals:
/**
* @brief Signal emitted when a message is received from a client
@@ -56,7 +58,8 @@ class Websocket : public QObject
* @param conn The client connection
* @param message The received message
*/
void on_message(QWebSocket *conn, QString message);
void on_binary_message(QWebSocket *conn, QByteArray message);
void on_text_message(QWebSocket *conn, QString message);
/**
* @brief Signal emitted when the server is closed
*
@@ -74,6 +77,7 @@ class Websocket : public QObject
*
* @param message The received message
*/
void processBinaryMessage(QByteArray message);
void processTextMessage(QString message);
/**
* @brief Private Slot called when a client disconnects