mirror of
https://github.com/Sani7/remote-ui.git
synced 2026-10-27 06:01:14 +01:00
Move to Qt
Everything seems to be working Only timer is not moved over
This commit is contained in:
@@ -5,6 +5,15 @@ include(FetchContent)
|
|||||||
FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.2/json.tar.xz DOWNLOAD_EXTRACT_TIMESTAMP TRUE)
|
FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.2/json.tar.xz DOWNLOAD_EXTRACT_TIMESTAMP TRUE)
|
||||||
FetchContent_MakeAvailable(json)
|
FetchContent_MakeAvailable(json)
|
||||||
|
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS Core)
|
||||||
|
|
||||||
|
set_target_properties(
|
||||||
|
UI
|
||||||
|
PROPERTIES
|
||||||
|
AUTOMOC ON
|
||||||
|
AUTORCC ON
|
||||||
|
)
|
||||||
|
|
||||||
target_compile_options(UI PRIVATE $<$<CONFIG:Debug>:
|
target_compile_options(UI PRIVATE $<$<CONFIG:Debug>:
|
||||||
-Wall -Wextra -pedantic-errors -Wconversion -Wsign-conversion
|
-Wall -Wextra -pedantic-errors -Wconversion -Wsign-conversion
|
||||||
>)
|
>)
|
||||||
@@ -12,16 +21,27 @@ target_compile_options(UI PRIVATE $<$<CONFIG:Debug>:
|
|||||||
target_sources(UI
|
target_sources(UI
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${CMAKE_CURRENT_LIST_DIR}/UI_item.cpp
|
${CMAKE_CURRENT_LIST_DIR}/UI_item.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/UI_item.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/UI_button.cpp
|
${CMAKE_CURRENT_LIST_DIR}/UI_button.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/UI_button.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/UI_checkbox.cpp
|
${CMAKE_CURRENT_LIST_DIR}/UI_checkbox.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/UI_checkbox.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/UI_combobox.cpp
|
${CMAKE_CURRENT_LIST_DIR}/UI_combobox.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/UI_combobox.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/UI_dial.cpp
|
${CMAKE_CURRENT_LIST_DIR}/UI_dial.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/UI_dial.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/UI_label.cpp
|
${CMAKE_CURRENT_LIST_DIR}/UI_label.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/UI_label.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/UI_led.cpp
|
${CMAKE_CURRENT_LIST_DIR}/UI_led.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/UI_led.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/UI_slider.cpp
|
${CMAKE_CURRENT_LIST_DIR}/UI_slider.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/UI_slider.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/UI_textbox.cpp
|
${CMAKE_CURRENT_LIST_DIR}/UI_textbox.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/UI_textbox.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/UI_thermo.cpp
|
${CMAKE_CURRENT_LIST_DIR}/UI_thermo.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/UI_thermo.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/UI_x_boxes.cpp
|
${CMAKE_CURRENT_LIST_DIR}/UI_x_boxes.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/UI_x_boxes.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(UI
|
target_include_directories(UI
|
||||||
@@ -36,4 +56,5 @@ target_link_libraries(UI
|
|||||||
PUBLIC
|
PUBLIC
|
||||||
Color
|
Color
|
||||||
nlohmann_json::nlohmann_json
|
nlohmann_json::nlohmann_json
|
||||||
|
Qt::Core
|
||||||
)
|
)
|
||||||
+6
-10
@@ -1,13 +1,12 @@
|
|||||||
#include "UI_button.hpp"
|
#include "UI_button.hpp"
|
||||||
|
|
||||||
UI_button::UI_button(std::string id, std::string text, Color fg_color, Color bg_color,
|
UI_button::UI_button(std::string id, std::string text, Color fg_color, Color bg_color, QObject* parrent)
|
||||||
std::function<void(std::string)> on_click)
|
: UI_item(id, UI_BUTTON_TYPE, text, 12, fg_color, bg_color, parrent)
|
||||||
: UI_item(id, UI_BUTTON_TYPE, text, 12, fg_color, bg_color)
|
|
||||||
{
|
{
|
||||||
this->m_on_click = on_click;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_button::UI_button(const json &j) : UI_item(UI_BUTTON_TYPE), m_on_click(nullptr)
|
UI_button::UI_button(const json &j, QObject* parrent) : UI_item(UI_BUTTON_TYPE, parrent)
|
||||||
{
|
{
|
||||||
from_json(j);
|
from_json(j);
|
||||||
}
|
}
|
||||||
@@ -23,10 +22,7 @@ json UI_button::to_json() const
|
|||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI_button::click() const
|
void UI_button::click()
|
||||||
{
|
{
|
||||||
if (m_on_click != nullptr)
|
emit on_click(m_id);
|
||||||
{
|
|
||||||
std::thread([this] { m_on_click(m_id); }).detach();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,16 @@
|
|||||||
|
|
||||||
class UI_button : public UI_item
|
class UI_button : public UI_item
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
UI_button(std::string id, std::string text, Color fg_color, Color bg_color,
|
UI_button(std::string id, std::string text, Color fg_color, Color bg_color, QObject* parrent = nullptr);
|
||||||
std::function<void(std::string)> on_click = nullptr);
|
UI_button(const json &j, QObject* parrent = nullptr);
|
||||||
UI_button(const json &j);
|
|
||||||
|
|
||||||
void from_json(const json &j) override;
|
void from_json(const json &j) override;
|
||||||
json to_json() const override;
|
json to_json() const override;
|
||||||
|
|
||||||
void click() const override;
|
void click() override;
|
||||||
|
|
||||||
private:
|
signals:
|
||||||
std::function<void(std::string)> m_on_click = nullptr;
|
void on_click(std::string id);
|
||||||
};
|
};
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
#include "UI_checkbox.hpp"
|
#include "UI_checkbox.hpp"
|
||||||
|
|
||||||
UI_checkbox::UI_checkbox() : UI_x_boxes(UI_CHECKBOX_TYPE), m_selected(), m_on_change(nullptr)
|
UI_checkbox::UI_checkbox(QObject* parrent) : UI_x_boxes(UI_CHECKBOX_TYPE, parrent), m_selected()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_checkbox::UI_checkbox(std::string id, std::string text, Color fg_color, Color bg_color,
|
UI_checkbox::UI_checkbox(std::string id, std::string text, Color fg_color, Color bg_color,
|
||||||
std::vector<std::string> options,
|
std::vector<std::string> options, QObject* parrent)
|
||||||
std::function<void(std::string, std::vector<std::string>)> on_change)
|
: UI_x_boxes(id, UI_CHECKBOX_TYPE, text, fg_color, bg_color, options, parrent), m_selected()
|
||||||
: UI_x_boxes(id, UI_CHECKBOX_TYPE, text, fg_color, bg_color, options), m_selected(), m_on_change(on_change)
|
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_options.size(); i++)
|
for (size_t i = 0; i < m_options.size(); i++)
|
||||||
{
|
{
|
||||||
@@ -15,7 +14,7 @@ UI_checkbox::UI_checkbox(std::string id, std::string text, Color fg_color, Color
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_checkbox::UI_checkbox(const json &j) : UI_x_boxes(UI_CHECKBOX_TYPE), m_selected(), m_on_change(nullptr)
|
UI_checkbox::UI_checkbox(const json &j, QObject* parrent) : UI_x_boxes(UI_CHECKBOX_TYPE, parrent), m_selected()
|
||||||
{
|
{
|
||||||
from_json(j);
|
from_json(j);
|
||||||
}
|
}
|
||||||
@@ -25,10 +24,8 @@ void UI_checkbox::toggle_selected(size_t selected)
|
|||||||
if (selected >= m_options.size())
|
if (selected >= m_options.size())
|
||||||
return;
|
return;
|
||||||
m_selected[selected] = !m_selected[selected];
|
m_selected[selected] = !m_selected[selected];
|
||||||
if (m_on_change != nullptr)
|
emit value_changed();
|
||||||
{
|
emit on_change(m_id, selected_text()[selected]);
|
||||||
std::thread([this] { m_on_change(m_id, selected_text()); }).detach();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI_checkbox::toggle_selected(std::string selected)
|
void UI_checkbox::toggle_selected(std::string selected)
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
|
|
||||||
class UI_checkbox : public UI_x_boxes
|
class UI_checkbox : public UI_x_boxes
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
UI_checkbox();
|
UI_checkbox(QObject* parrent = nullptr);
|
||||||
UI_checkbox(std::string id, std::string text, Color fg_color, Color bg_color, std::vector<std::string> options,
|
UI_checkbox(std::string id, std::string text, Color fg_color, Color bg_color, std::vector<std::string> options, QObject* parrent = nullptr);
|
||||||
std::function<void(std::string, std::vector<std::string>)> on_change = nullptr);
|
UI_checkbox(const json &j, QObject* parrent = nullptr);
|
||||||
UI_checkbox(const json &j);
|
|
||||||
|
|
||||||
void toggle_selected(size_t selected);
|
void toggle_selected(size_t selected);
|
||||||
void toggle_selected(std::string selected);
|
void toggle_selected(std::string selected);
|
||||||
@@ -21,8 +21,9 @@ class UI_checkbox : public UI_x_boxes
|
|||||||
void from_json(const json &j) override;
|
void from_json(const json &j) override;
|
||||||
json to_json() const override;
|
json to_json() const override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void on_change(std::string, std::string);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<bool> m_selected;
|
std::vector<bool> m_selected;
|
||||||
|
|
||||||
std::function<void(std::string, std::vector<std::string>)> m_on_change;
|
|
||||||
};
|
};
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
#include "UI_combobox.hpp"
|
#include "UI_combobox.hpp"
|
||||||
|
|
||||||
UI_combobox::UI_combobox() : UI_x_boxes(UI_COMBOBOX_TYPE)
|
UI_combobox::UI_combobox(QObject* parrent) : UI_x_boxes(UI_COMBOBOX_TYPE, parrent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_combobox::UI_combobox(std::string id, std::string text, Color fg_color, Color bg_color,
|
UI_combobox::UI_combobox(std::string id, std::string text, Color fg_color, Color bg_color,
|
||||||
std::vector<std::string> options, size_t selected,
|
std::vector<std::string> options, size_t selected, QObject* parrent)
|
||||||
std::function<void(std::string, std::string)> on_change)
|
: UI_x_boxes(id, UI_COMBOBOX_TYPE, text, fg_color, bg_color, options, parrent), m_selected(selected)
|
||||||
: UI_x_boxes(id, UI_COMBOBOX_TYPE, text, fg_color, bg_color, options), m_selected(selected), m_on_change(on_change)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_combobox::UI_combobox(const json &j) : UI_x_boxes(UI_COMBOBOX_TYPE), m_on_change(nullptr)
|
UI_combobox::UI_combobox(const json &j, QObject* parrent) : UI_x_boxes(UI_COMBOBOX_TYPE, parrent)
|
||||||
{
|
{
|
||||||
from_json(j);
|
from_json(j);
|
||||||
}
|
}
|
||||||
@@ -21,10 +20,8 @@ void UI_combobox::set_selected(size_t selected)
|
|||||||
if (selected == m_selected)
|
if (selected == m_selected)
|
||||||
return;
|
return;
|
||||||
m_selected = selected;
|
m_selected = selected;
|
||||||
if (m_on_change != nullptr)
|
emit value_changed();
|
||||||
{
|
emit on_change(m_id, selected_text());
|
||||||
std::thread([this] { m_on_change(m_id, selected_text()); }).detach();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI_combobox::set_selected(std::string selected)
|
void UI_combobox::set_selected(std::string selected)
|
||||||
|
|||||||
@@ -8,11 +8,12 @@
|
|||||||
|
|
||||||
class UI_combobox : public UI_x_boxes
|
class UI_combobox : public UI_x_boxes
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
UI_combobox();
|
UI_combobox(QObject* parrent = nullptr);
|
||||||
UI_combobox(std::string id, std::string text, Color fg_color, Color bg_color, std::vector<std::string> options,
|
UI_combobox(std::string id, std::string text, Color fg_color, Color bg_color, std::vector<std::string> options,
|
||||||
size_t selected = 0, std::function<void(std::string, std::string)> on_change = nullptr);
|
size_t selected = 0, QObject* parrent = nullptr);
|
||||||
UI_combobox(const json &j);
|
UI_combobox(const json &j, QObject* parrent = nullptr);
|
||||||
|
|
||||||
void set_selected(size_t selected);
|
void set_selected(size_t selected);
|
||||||
void set_selected(std::string selected) override;
|
void set_selected(std::string selected) override;
|
||||||
@@ -21,9 +22,8 @@ class UI_combobox : public UI_x_boxes
|
|||||||
|
|
||||||
void from_json(const json &j) override;
|
void from_json(const json &j) override;
|
||||||
json to_json() const override;
|
json to_json() const override;
|
||||||
|
signals:
|
||||||
|
void on_change(std::string id, std::string selected);
|
||||||
private:
|
private:
|
||||||
size_t m_selected;
|
size_t m_selected;
|
||||||
|
|
||||||
std::function<void(std::string, std::string)> m_on_change;
|
|
||||||
};
|
};
|
||||||
+4
-3
@@ -1,11 +1,11 @@
|
|||||||
#include "UI_dial.hpp"
|
#include "UI_dial.hpp"
|
||||||
|
|
||||||
UI_dial::UI_dial(std::string id, std::string text, Color fg_color, Color bg_color, double min, double max, double value)
|
UI_dial::UI_dial(std::string id, std::string text, Color fg_color, Color bg_color, double min, double max, double value, QObject* parrent)
|
||||||
: UI_item(id, UI_DIAL_TYPE, text, 12, fg_color, bg_color), m_min(min), m_max(max), m_value(value)
|
: UI_item(id, UI_DIAL_TYPE, text, 12, fg_color, bg_color, parrent), m_min(min), m_max(max), m_value(value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_dial::UI_dial(const json &j) : UI_item(UI_DIAL_TYPE)
|
UI_dial::UI_dial(const json &j, QObject* parrent) : UI_item(UI_DIAL_TYPE, parrent)
|
||||||
{
|
{
|
||||||
from_json(j);
|
from_json(j);
|
||||||
}
|
}
|
||||||
@@ -18,6 +18,7 @@ void UI_dial::set_value(double value)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
this->m_value = value;
|
this->m_value = value;
|
||||||
|
emit value_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
double UI_dial::value() const
|
double UI_dial::value() const
|
||||||
|
|||||||
+3
-2
@@ -5,9 +5,10 @@
|
|||||||
|
|
||||||
class UI_dial : public UI_item
|
class UI_dial : public UI_item
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
UI_dial(std::string id, std::string text, Color fg_color, Color bg_color, double min, double max, double value);
|
UI_dial(std::string id, std::string text, Color fg_color, Color bg_color, double min, double max, double value, QObject* parrent = nullptr);
|
||||||
UI_dial(const json &j);
|
UI_dial(const json &j, QObject* parrent = nullptr);
|
||||||
|
|
||||||
void set_value(double value) override;
|
void set_value(double value) override;
|
||||||
double value() const;
|
double value() const;
|
||||||
|
|||||||
+25
-6
@@ -1,22 +1,29 @@
|
|||||||
#include "UI_item.hpp"
|
#include "UI_item.hpp"
|
||||||
|
|
||||||
UI_item::UI_item(std::string id, std::string type, std::string text, uint8_t text_size, Color fg_color, Color bg_color)
|
UI_item::UI_item(std::string id, std::string type, std::string text, uint8_t text_size, Color fg_color, Color bg_color, QObject* parrent)
|
||||||
: m_id(id), m_type(type), m_text(text), m_text_size(text_size), m_fg_color(fg_color), m_bg_color(bg_color),
|
: QObject(parrent),
|
||||||
|
m_id(id), m_type(type), m_text(text), m_text_size(text_size), m_fg_color(fg_color), m_bg_color(bg_color),
|
||||||
enabled(true), visible(true)
|
enabled(true), visible(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_item::UI_item(std::string type)
|
UI_item::UI_item(std::string type, QObject* parrent)
|
||||||
: m_id(""), m_type(type), m_text(""), m_text_size(12), m_fg_color(Color::Black), m_bg_color(Color::White),
|
: QObject(parrent),
|
||||||
|
m_id(""), m_type(type), m_text(""), m_text_size(12), m_fg_color(Color::Black), m_bg_color(Color::White),
|
||||||
enabled(true), visible(true)
|
enabled(true), visible(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_item::UI_item(const json &j)
|
UI_item::UI_item(const json &j, QObject* parrent) :
|
||||||
|
QObject(parrent)
|
||||||
{
|
{
|
||||||
from_json(j);
|
from_json(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UI_item::~UI_item()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
std::string UI_item::id() const
|
std::string UI_item::id() const
|
||||||
{
|
{
|
||||||
return m_id;
|
return m_id;
|
||||||
@@ -41,6 +48,7 @@ void UI_item::set_text(std::string text)
|
|||||||
if (this->m_text != text)
|
if (this->m_text != text)
|
||||||
{
|
{
|
||||||
this->m_text = text;
|
this->m_text = text;
|
||||||
|
emit value_changed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +62,7 @@ void UI_item::set_text_size(uint8_t text_size)
|
|||||||
if (this->m_text_size != text_size)
|
if (this->m_text_size != text_size)
|
||||||
{
|
{
|
||||||
this->m_text_size = text_size;
|
this->m_text_size = text_size;
|
||||||
|
emit value_changed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +76,7 @@ void UI_item::set_fg_color(Color fg_color)
|
|||||||
if (this->m_fg_color != fg_color)
|
if (this->m_fg_color != fg_color)
|
||||||
{
|
{
|
||||||
this->m_fg_color = fg_color;
|
this->m_fg_color = fg_color;
|
||||||
|
emit value_changed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,6 +90,7 @@ void UI_item::set_bg_color(Color bg_color)
|
|||||||
if (this->m_bg_color != bg_color)
|
if (this->m_bg_color != bg_color)
|
||||||
{
|
{
|
||||||
this->m_bg_color = bg_color;
|
this->m_bg_color = bg_color;
|
||||||
|
emit value_changed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +101,11 @@ Color UI_item::bg_color() const
|
|||||||
|
|
||||||
void UI_item::set_enabled(bool enabled)
|
void UI_item::set_enabled(bool enabled)
|
||||||
{
|
{
|
||||||
|
if (this->enabled != enabled)
|
||||||
|
{
|
||||||
this->enabled = enabled;
|
this->enabled = enabled;
|
||||||
|
emit value_changed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UI_item::is_enabled() const
|
bool UI_item::is_enabled() const
|
||||||
@@ -100,7 +115,11 @@ bool UI_item::is_enabled() const
|
|||||||
|
|
||||||
void UI_item::set_visible(bool visible)
|
void UI_item::set_visible(bool visible)
|
||||||
{
|
{
|
||||||
|
if (this->visible != visible)
|
||||||
|
{
|
||||||
this->visible = visible;
|
this->visible = visible;
|
||||||
|
emit value_changed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UI_item::is_visible() const
|
bool UI_item::is_visible() const
|
||||||
@@ -139,7 +158,7 @@ json UI_item::to_json() const
|
|||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI_item::click() const {};
|
void UI_item::click() {};
|
||||||
|
|
||||||
void UI_item::set_selected(std::string selected)
|
void UI_item::set_selected(std::string selected)
|
||||||
{
|
{
|
||||||
|
|||||||
+12
-5
@@ -5,16 +5,20 @@
|
|||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
|
||||||
#define UNUSED(x) (void)(x)
|
#define UNUSED(x) (void)(x)
|
||||||
|
|
||||||
class UI_item
|
class UI_item : public QObject
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
UI_item(std::string type);
|
explicit UI_item(std::string type, QObject* parrent = nullptr);
|
||||||
UI_item(std::string id, std::string type, std::string text, uint8_t text_size, Color fg_color, Color bg_color);
|
explicit UI_item(std::string id, std::string type, std::string text, uint8_t text_size, Color fg_color, Color bg_color, QObject* parrent = nullptr);
|
||||||
UI_item(const json &j);
|
explicit UI_item(const json &j, QObject* parrent = nullptr);
|
||||||
|
~UI_item();
|
||||||
|
|
||||||
std::string id() const;
|
std::string id() const;
|
||||||
std::string type() const;
|
std::string type() const;
|
||||||
@@ -42,10 +46,13 @@ class UI_item
|
|||||||
|
|
||||||
virtual json to_json() const;
|
virtual json to_json() const;
|
||||||
|
|
||||||
virtual void click() const;
|
virtual void click();
|
||||||
virtual void set_selected(std::string selected);
|
virtual void set_selected(std::string selected);
|
||||||
virtual void set_value(double value);
|
virtual void set_value(double value);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void value_changed();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string m_id;
|
std::string m_id;
|
||||||
std::string m_type;
|
std::string m_type;
|
||||||
|
|||||||
+3
-3
@@ -1,11 +1,11 @@
|
|||||||
#include "UI_label.hpp"
|
#include "UI_label.hpp"
|
||||||
|
|
||||||
UI_label::UI_label(std::string id, std::string text, Color fg_color, Color bg_color)
|
UI_label::UI_label(std::string id, std::string text, Color fg_color, Color bg_color, QObject* parrent)
|
||||||
: UI_item(id, UI_LABEL_TYPE, text, 12, fg_color, bg_color)
|
: UI_item(id, UI_LABEL_TYPE, text, 12, fg_color, bg_color, parrent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_label::UI_label(const json &j) : UI_item(UI_LABEL_TYPE)
|
UI_label::UI_label(const json &j, QObject* parrent) : UI_item(UI_LABEL_TYPE, parrent)
|
||||||
{
|
{
|
||||||
from_json(j);
|
from_json(j);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -6,9 +6,10 @@
|
|||||||
|
|
||||||
class UI_label : public UI_item
|
class UI_label : public UI_item
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
UI_label(std::string id, std::string text, Color fg_color, Color bg_color);
|
UI_label(std::string id, std::string text, Color fg_color, Color bg_color, QObject* parrent = nullptr);
|
||||||
UI_label(const json &j);
|
UI_label(const json &j, QObject* parrent = nullptr);
|
||||||
|
|
||||||
void from_json(const json &j) override;
|
void from_json(const json &j) override;
|
||||||
json to_json() const override;
|
json to_json() const override;
|
||||||
|
|||||||
+7
-3
@@ -1,11 +1,11 @@
|
|||||||
#include "UI_led.hpp"
|
#include "UI_led.hpp"
|
||||||
|
|
||||||
UI_led::UI_led(std::string id, std::string text, Color fg_color, Color bg_color, Color led_color)
|
UI_led::UI_led(std::string id, std::string text, Color fg_color, Color bg_color, Color led_color, QObject* parrent)
|
||||||
: UI_item(id, UI_LED_TYPE, text, 12, fg_color, bg_color), m_led_color(led_color)
|
: UI_item(id, UI_LED_TYPE, text, 12, fg_color, bg_color, parrent), m_led_color(led_color)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_led::UI_led(const json &j) : UI_item(UI_LED_TYPE)
|
UI_led::UI_led(const json &j, QObject* parrent) : UI_item(UI_LED_TYPE, parrent)
|
||||||
{
|
{
|
||||||
from_json(j);
|
from_json(j);
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,11 @@ Color UI_led::led_color() const
|
|||||||
|
|
||||||
void UI_led::set_led_color(Color led_color)
|
void UI_led::set_led_color(Color led_color)
|
||||||
{
|
{
|
||||||
|
if (m_led_color != led_color)
|
||||||
|
{
|
||||||
m_led_color = led_color;
|
m_led_color = led_color;
|
||||||
|
emit value_changed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI_led::from_json(const json &j)
|
void UI_led::from_json(const json &j)
|
||||||
|
|||||||
+3
-2
@@ -6,9 +6,10 @@
|
|||||||
|
|
||||||
class UI_led : public UI_item
|
class UI_led : public UI_item
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
UI_led(std::string id, std::string text, Color fg_color, Color bg_color, Color led_color);
|
UI_led(std::string id, std::string text, Color fg_color, Color bg_color, Color led_color, QObject* parrent = nullptr);
|
||||||
UI_led(const json &j);
|
UI_led(const json &j, QObject* parrent = nullptr);
|
||||||
|
|
||||||
Color led_color() const;
|
Color led_color() const;
|
||||||
void set_led_color(Color led_color);
|
void set_led_color(Color led_color);
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#include "UI_slider.hpp"
|
#include "UI_slider.hpp"
|
||||||
|
|
||||||
UI_slider::UI_slider(std::string id, std::string text, Color fg_color, Color bg_color, double min, double max,
|
UI_slider::UI_slider(std::string id, std::string text, Color fg_color, Color bg_color, double min, double max,
|
||||||
double value, std::function<void(std::string, double)> on_change)
|
double value, QObject* parrent)
|
||||||
: UI_item(id, UI_SLIDER_TYPE, text, 12, fg_color, bg_color), m_min(min), m_max(max), m_value(value)
|
: UI_item(id, UI_SLIDER_TYPE, text, 12, fg_color, bg_color, parrent), m_min(min), m_max(max), m_value(value)
|
||||||
{
|
{
|
||||||
this->m_on_change = on_change;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_slider::UI_slider(const json &j) : UI_item(UI_SLIDER_TYPE), m_on_change(nullptr)
|
UI_slider::UI_slider(const json &j, QObject* parrent) : UI_item(UI_SLIDER_TYPE, parrent)
|
||||||
{
|
{
|
||||||
from_json(j);
|
from_json(j);
|
||||||
}
|
}
|
||||||
@@ -20,10 +20,8 @@ void UI_slider::set_value(double value)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
this->m_value = value;
|
this->m_value = value;
|
||||||
if (m_on_change != nullptr)
|
emit value_changed();
|
||||||
{
|
emit on_change(m_id, m_value);
|
||||||
std::thread([this] { m_on_change(m_id, m_value); }).detach();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double UI_slider::value() const
|
double UI_slider::value() const
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
class UI_slider : public UI_item
|
class UI_slider : public UI_item
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
UI_slider(std::string id, std::string text, Color fg_color, Color bg_color, double min, double max, double value,
|
UI_slider(std::string id, std::string text, Color fg_color, Color bg_color, double min, double max, double value, QObject* parrent = nullptr);
|
||||||
std::function<void(std::string, double)> on_change = nullptr);
|
UI_slider(const json &j, QObject* parrent = nullptr);
|
||||||
UI_slider(const json &j);
|
|
||||||
|
|
||||||
void set_value(double value) override;
|
void set_value(double value) override;
|
||||||
double value() const;
|
double value() const;
|
||||||
@@ -18,11 +18,11 @@ class UI_slider : public UI_item
|
|||||||
|
|
||||||
void from_json(const json &j) override;
|
void from_json(const json &j) override;
|
||||||
json to_json() const override;
|
json to_json() const override;
|
||||||
|
signals:
|
||||||
|
void on_change(std::string id, double value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double m_min;
|
double m_min;
|
||||||
double m_max;
|
double m_max;
|
||||||
double m_value;
|
double m_value;
|
||||||
|
|
||||||
std::function<void(std::string, double)> m_on_change;
|
|
||||||
};
|
};
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
#include "UI_textbox.hpp"
|
#include "UI_textbox.hpp"
|
||||||
|
|
||||||
UI_textbox::UI_textbox(std::string id, std::string hint, Color fg_color, Color bg_color,
|
UI_textbox::UI_textbox(std::string id, std::string hint, Color fg_color, Color bg_color, QObject* parrent)
|
||||||
std::function<void(std::string, std::string)> on_change)
|
: UI_item(id, UI_TEXTBOX_TYPE, "", 0, fg_color, bg_color, parrent), m_hint(hint)
|
||||||
: UI_item(id, UI_TEXTBOX_TYPE, "", 0, fg_color, bg_color), m_hint(hint), m_on_change(on_change)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_textbox::UI_textbox(const json &j) : UI_item(UI_TEXTBOX_TYPE), m_on_change(nullptr)
|
UI_textbox::UI_textbox(const json &j, QObject* parrent) : UI_item(UI_TEXTBOX_TYPE, parrent)
|
||||||
{
|
{
|
||||||
from_json(j);
|
from_json(j);
|
||||||
}
|
}
|
||||||
@@ -16,15 +15,14 @@ void UI_textbox::set_text(std::string text)
|
|||||||
if (text == m_text)
|
if (text == m_text)
|
||||||
return;
|
return;
|
||||||
m_text = text;
|
m_text = text;
|
||||||
if (m_on_change != nullptr)
|
emit value_changed();
|
||||||
{
|
emit on_change(m_id, m_text);
|
||||||
std::thread([this] { m_on_change(m_id, m_text); }).detach();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI_textbox::set_hint(std::string hint)
|
void UI_textbox::set_hint(std::string hint)
|
||||||
{
|
{
|
||||||
m_hint = hint;
|
m_hint = hint;
|
||||||
|
emit value_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string UI_textbox::hint() const
|
std::string UI_textbox::hint() const
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
|
|
||||||
class UI_textbox : public UI_item
|
class UI_textbox : public UI_item
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
UI_textbox(std::string id, std::string hint, Color fg_color, Color bg_color,
|
UI_textbox(std::string id, std::string hint, Color fg_color, Color bg_color, QObject* parrent = nullptr);
|
||||||
std::function<void(std::string, std::string)> on_change = nullptr);
|
UI_textbox(const json &j, QObject* parrent = nullptr);
|
||||||
UI_textbox(const json &j);
|
|
||||||
|
|
||||||
void set_text(std::string text) override;
|
void set_text(std::string text) override;
|
||||||
|
|
||||||
@@ -18,8 +18,9 @@ class UI_textbox : public UI_item
|
|||||||
|
|
||||||
void from_json(const json &j) override;
|
void from_json(const json &j) override;
|
||||||
json to_json() const override;
|
json to_json() const override;
|
||||||
|
signals:
|
||||||
|
void on_change(std::string id, std::string text);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_hint;
|
std::string m_hint;
|
||||||
std::function<void(std::string, std::string)> m_on_change;
|
|
||||||
};
|
};
|
||||||
+10
-3
@@ -1,12 +1,12 @@
|
|||||||
#include "UI_thermo.hpp"
|
#include "UI_thermo.hpp"
|
||||||
|
|
||||||
UI_thermo::UI_thermo(std::string id, std::string text, Color fg_color, Color bg_color, double min, double max,
|
UI_thermo::UI_thermo(std::string id, std::string text, Color fg_color, Color bg_color, double min, double max,
|
||||||
double value)
|
double value, QObject* parrent)
|
||||||
: UI_item(id, UI_THERMO_TYPE, text, 12, fg_color, bg_color), m_min(min), m_max(max), m_value(value)
|
: UI_item(id, UI_THERMO_TYPE, text, 12, fg_color, bg_color, parrent), m_min(min), m_max(max), m_value(value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_thermo::UI_thermo(const json &j) : UI_item(UI_THERMO_TYPE)
|
UI_thermo::UI_thermo(const json &j, QObject* parrent) : UI_item(UI_THERMO_TYPE, parrent)
|
||||||
{
|
{
|
||||||
from_json(j);
|
from_json(j);
|
||||||
}
|
}
|
||||||
@@ -19,6 +19,7 @@ void UI_thermo::set_value(double value)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
this->m_value = value;
|
this->m_value = value;
|
||||||
|
emit value_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
double UI_thermo::value() const
|
double UI_thermo::value() const
|
||||||
@@ -39,11 +40,13 @@ double UI_thermo::max() const
|
|||||||
void UI_thermo::set_start_color(Color color)
|
void UI_thermo::set_start_color(Color color)
|
||||||
{
|
{
|
||||||
this->m_color_map[0] = color;
|
this->m_color_map[0] = color;
|
||||||
|
emit value_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI_thermo::set_end_color(Color color)
|
void UI_thermo::set_end_color(Color color)
|
||||||
{
|
{
|
||||||
this->m_color_map[1] = color;
|
this->m_color_map[1] = color;
|
||||||
|
emit value_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI_thermo::add_color_stop(double value, Color color)
|
void UI_thermo::add_color_stop(double value, Color color)
|
||||||
@@ -52,6 +55,7 @@ void UI_thermo::add_color_stop(double value, Color color)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
this->m_color_map[value] = color;
|
this->m_color_map[value] = color;
|
||||||
|
emit value_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI_thermo::add_color_stop_normalized(double value, Color color)
|
void UI_thermo::add_color_stop_normalized(double value, Color color)
|
||||||
@@ -61,6 +65,7 @@ void UI_thermo::add_color_stop_normalized(double value, Color color)
|
|||||||
|
|
||||||
double normalized = (value - m_min) / (m_max - m_min);
|
double normalized = (value - m_min) / (m_max - m_min);
|
||||||
this->m_color_map[normalized] = color;
|
this->m_color_map[normalized] = color;
|
||||||
|
emit value_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI_thermo::remove_color_stop(double value)
|
void UI_thermo::remove_color_stop(double value)
|
||||||
@@ -69,6 +74,7 @@ void UI_thermo::remove_color_stop(double value)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
this->m_color_map.erase(value);
|
this->m_color_map.erase(value);
|
||||||
|
emit value_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI_thermo::remove_color_stop_normalized(double value)
|
void UI_thermo::remove_color_stop_normalized(double value)
|
||||||
@@ -78,6 +84,7 @@ void UI_thermo::remove_color_stop_normalized(double value)
|
|||||||
|
|
||||||
double normalized = (value - m_min) / (m_max - m_min);
|
double normalized = (value - m_min) / (m_max - m_min);
|
||||||
this->m_color_map.erase(normalized);
|
this->m_color_map.erase(normalized);
|
||||||
|
emit value_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI_thermo::from_json(const json &j)
|
void UI_thermo::from_json(const json &j)
|
||||||
|
|||||||
@@ -6,9 +6,10 @@
|
|||||||
// TODO: Add color scale
|
// TODO: Add color scale
|
||||||
class UI_thermo : public UI_item
|
class UI_thermo : public UI_item
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
UI_thermo(std::string id, std::string text, Color fg_color, Color bg_color, double min, double max, double value);
|
UI_thermo(std::string id, std::string text, Color fg_color, Color bg_color, double min, double max, double value, QObject* parrent = nullptr);
|
||||||
UI_thermo(const json &j);
|
UI_thermo(const json &j, QObject* parrent = nullptr);
|
||||||
|
|
||||||
void set_value(double value) override;
|
void set_value(double value) override;
|
||||||
double value() const;
|
double value() const;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#include "UI_x_boxes.hpp"
|
#include "UI_x_boxes.hpp"
|
||||||
|
|
||||||
UI_x_boxes::UI_x_boxes(std::string type) : UI_item(type), m_options()
|
UI_x_boxes::UI_x_boxes(std::string type, QObject* parrent) : UI_item(type, parrent), m_options()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_x_boxes::UI_x_boxes(std::string id, std::string type, std::string text, Color fg_color, Color bg_color,
|
UI_x_boxes::UI_x_boxes(std::string id, std::string type, std::string text, Color fg_color, Color bg_color,
|
||||||
std::vector<std::string> options)
|
std::vector<std::string> options, QObject* parrent)
|
||||||
: UI_item(id, type, text, 12, fg_color, bg_color), m_options(options)
|
: UI_item(id, type, text, 12, fg_color, bg_color, parrent), m_options(options)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,11 @@
|
|||||||
|
|
||||||
class UI_x_boxes : public UI_item
|
class UI_x_boxes : public UI_item
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
UI_x_boxes(std::string type);
|
UI_x_boxes(std::string type, QObject* parrent = nullptr);
|
||||||
UI_x_boxes(std::string id, std::string type, std::string text, Color fg_color, Color bg_color,
|
UI_x_boxes(std::string id, std::string type, std::string text, Color fg_color, Color bg_color,
|
||||||
std::vector<std::string> options);
|
std::vector<std::string> options, QObject* parrent = nullptr);
|
||||||
|
|
||||||
void from_json(const json &j) override;
|
void from_json(const json &j) override;
|
||||||
json to_json() const override;
|
json to_json() const override;
|
||||||
|
|||||||
@@ -4,11 +4,14 @@ include_directories(${GTEST_INCLUDE_DIR})
|
|||||||
link_directories(${GTEST_LIB_DIR})
|
link_directories(${GTEST_LIB_DIR})
|
||||||
|
|
||||||
find_package(GTest REQUIRED)
|
find_package(GTest REQUIRED)
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS Core)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
# tests
|
# tests
|
||||||
file(GLOB_RECURSE TEST_SOURCES "*.cpp")
|
file(GLOB_RECURSE TEST_SOURCES "*.[hc]pp")
|
||||||
add_executable(tests ${TEST_SOURCES})
|
add_executable(tests ${TEST_SOURCES})
|
||||||
target_link_libraries(tests ${LIBS})
|
|
||||||
|
|
||||||
target_compile_options(tests PRIVATE $<$<CONFIG:Debug>:
|
target_compile_options(tests PRIVATE $<$<CONFIG:Debug>:
|
||||||
-Wall -Wextra -pedantic-errors -Wconversion -Wsign-conversion
|
-Wall -Wextra -pedantic-errors -Wconversion -Wsign-conversion
|
||||||
@@ -19,6 +22,7 @@ target_link_libraries(tests
|
|||||||
UI
|
UI
|
||||||
gtest
|
gtest
|
||||||
GTest::gtest_main
|
GTest::gtest_main
|
||||||
|
Qt::Core
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(tests
|
target_include_directories(tests
|
||||||
|
|||||||
+1
-13
@@ -1,4 +1,5 @@
|
|||||||
#include "Test.hpp"
|
#include "Test.hpp"
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
TEST(UI_button, to_from_json)
|
TEST(UI_button, to_from_json)
|
||||||
{
|
{
|
||||||
@@ -10,16 +11,3 @@ TEST(UI_button, to_from_json)
|
|||||||
EXPECT_EQ(button.fg_color(), button2.fg_color());
|
EXPECT_EQ(button.fg_color(), button2.fg_color());
|
||||||
EXPECT_EQ(button.bg_color(), button2.bg_color());
|
EXPECT_EQ(button.bg_color(), button2.bg_color());
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_click(std::string id)
|
|
||||||
{
|
|
||||||
UNUSED(id);
|
|
||||||
EXPECT_EQ(id, "button_id");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(UI_button, on_click)
|
|
||||||
{
|
|
||||||
UI_button button("button_id", "button_text", Color(255, 255, 255), Color(0, 0, 0), on_click);
|
|
||||||
button.click();
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
||||||
}
|
|
||||||
+1
-16
@@ -12,23 +12,8 @@ TEST(UI_slider, to_from_json)
|
|||||||
EXPECT_EQ(slider.value(), slider2.value());
|
EXPECT_EQ(slider.value(), slider2.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
static double val = 0;
|
|
||||||
void on_change(std::string id, double value)
|
|
||||||
{
|
|
||||||
EXPECT_EQ(id, "slider_id");
|
|
||||||
val = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(UI_slider, set_value)
|
|
||||||
{
|
|
||||||
UI_slider slider("slider_id", "slider_text", Color(255, 255, 255), Color(0, 0, 0), 0, 100, 50, on_change);
|
|
||||||
slider.set_value(75);
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
||||||
EXPECT_EQ(val, 75);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(UI_slider, value)
|
TEST(UI_slider, value)
|
||||||
{
|
{
|
||||||
UI_slider slider("slider_id", "slider_text", Color(255, 255, 255), Color(0, 0, 0), 0, 100, 50, on_change);
|
UI_slider slider("slider_id", "slider_text", Color(255, 255, 255), Color(0, 0, 0), 0, 100, 50);
|
||||||
EXPECT_EQ(slider.value(), 50);
|
EXPECT_EQ(slider.value(), 50);
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-3
@@ -1,18 +1,29 @@
|
|||||||
add_executable(server)
|
if (ANDROID)
|
||||||
|
message(FATAL_ERROR "This project cannot be built on Android.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS WebSockets)
|
||||||
|
|
||||||
|
qt_add_executable(server)
|
||||||
|
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
FetchContent_Declare(magic_enum URL https://github.com/Neargye/magic_enum/releases/download/v0.9.6/magic_enum-v0.9.6.tar.gz DOWNLOAD_EXTRACT_TIMESTAMP TRUE)
|
FetchContent_Declare(magic_enum URL https://github.com/Neargye/magic_enum/releases/download/v0.9.6/magic_enum-v0.9.6.tar.gz DOWNLOAD_EXTRACT_TIMESTAMP TRUE)
|
||||||
FetchContent_MakeAvailable(magic_enum)
|
FetchContent_MakeAvailable(magic_enum)
|
||||||
|
|
||||||
file(GLOB_RECURSE SIM_SOURCES "simulators/*.cpp")
|
file(GLOB_RECURSE SIM_SOURCES "simulators/*.[hc]pp")
|
||||||
|
|
||||||
target_sources(server PRIVATE
|
target_sources(server PRIVATE
|
||||||
${CMAKE_CURRENT_LIST_DIR}/main.cpp
|
${CMAKE_CURRENT_LIST_DIR}/main.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/message_parser.cpp
|
${CMAKE_CURRENT_LIST_DIR}/message_parser.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/simulator_base.cpp
|
${CMAKE_CURRENT_LIST_DIR}/simulator_base.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/simulator_base.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/simulators.cpp
|
${CMAKE_CURRENT_LIST_DIR}/simulators.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/simulators.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/websocket.cpp
|
${CMAKE_CURRENT_LIST_DIR}/websocket.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/websocket.hpp
|
||||||
${SIM_SOURCES}
|
${SIM_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,10 +36,10 @@ target_include_directories(server
|
|||||||
${CMAKE_CURRENT_LIST_DIR}
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
${CMAKE_CURRENT_LIST_DIR}/simulators
|
${CMAKE_CURRENT_LIST_DIR}/simulators
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${PROJECT_DIR}/external/websocketpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(server PRIVATE
|
target_link_libraries(server PRIVATE
|
||||||
|
Qt::WebSockets
|
||||||
UI
|
UI
|
||||||
Timer
|
Timer
|
||||||
magic_enum::magic_enum
|
magic_enum::magic_enum
|
||||||
|
|||||||
+16
-70
@@ -1,58 +1,15 @@
|
|||||||
#include <iostream>
|
#include <QtCore/QCoreApplication>
|
||||||
#include <signal.h>
|
#include <QtCore/QCommandLineParser>
|
||||||
#include <stdlib.h>
|
#include <QtCore/QCommandLineOption>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "spdlog/async.h"
|
#include "spdlog/async.h"
|
||||||
#include "spdlog/sinks/rotating_file_sink.h"
|
#include "spdlog/sinks/rotating_file_sink.h"
|
||||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
#include "spdlog/sinks/stdout_color_sinks.h"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
#include "message_parser.hpp"
|
|
||||||
#include "simulators.hpp"
|
#include "simulators.hpp"
|
||||||
#include "websocket.hpp"
|
#include "websocket.hpp"
|
||||||
|
|
||||||
class Spdlog_buffer : public std::stringbuf
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Spdlog_buffer(std::function<void(std::string)> log_function) : log_function(log_function)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
int sync()
|
|
||||||
{
|
|
||||||
std::string str = this->str();
|
|
||||||
str.pop_back();
|
|
||||||
log_function(str);
|
|
||||||
this->str("");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::function<void(std::string)> log_function;
|
|
||||||
};
|
|
||||||
|
|
||||||
Simulators *g_simulators;
|
|
||||||
Websocket *g_web_socket;
|
|
||||||
Spdlog_buffer g_info_buffer([](std::string message) { spdlog::info(message); });
|
|
||||||
Spdlog_buffer g_error_buffer([](std::string message) { spdlog::error(message); });
|
|
||||||
std::ostream g_out(&g_info_buffer);
|
|
||||||
std::ostream g_err(&g_error_buffer);
|
|
||||||
|
|
||||||
void int_handler(int s)
|
|
||||||
{
|
|
||||||
UNUSED(s);
|
|
||||||
std::cout << std::endl;
|
|
||||||
g_out << "Caught Ctrl + C" << std::endl;
|
|
||||||
if (g_web_socket != nullptr)
|
|
||||||
g_web_socket->stop();
|
|
||||||
if (g_simulators != nullptr)
|
|
||||||
g_simulators->stop();
|
|
||||||
g_out << "Shutting down." << std::endl;
|
|
||||||
// delay to allow the server to stop gracefully
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_logger()
|
void init_logger()
|
||||||
{
|
{
|
||||||
spdlog::init_thread_pool(8192, 1);
|
spdlog::init_thread_pool(8192, 1);
|
||||||
@@ -67,38 +24,27 @@ void init_logger()
|
|||||||
spdlog::set_level(spdlog::level::trace);
|
spdlog::set_level(spdlog::level::trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
// Setup the signal handler
|
QCoreApplication a(argc, argv);
|
||||||
struct sigaction sigIntHandler;
|
|
||||||
|
|
||||||
sigIntHandler.sa_handler = int_handler;
|
QCommandLineParser parser;
|
||||||
sigemptyset(&sigIntHandler.sa_mask);
|
parser.setApplicationDescription("QtWebSockets example: echoserver");
|
||||||
sigIntHandler.sa_flags = 0;
|
parser.addHelpOption();
|
||||||
|
|
||||||
sigaction(SIGINT, &sigIntHandler, NULL);
|
QCommandLineOption portOption(QStringList() << "p" << "port",
|
||||||
|
QCoreApplication::translate("main", "Port for echoserver [default: 9002]."),
|
||||||
|
QCoreApplication::translate("main", "port"), QLatin1String("9002"));
|
||||||
|
parser.addOption(portOption);
|
||||||
|
parser.process(a);
|
||||||
|
uint16_t port = parser.value(portOption).toUShort();
|
||||||
|
|
||||||
// Initialize the logger
|
// Initialize the logger
|
||||||
init_logger();
|
init_logger();
|
||||||
|
|
||||||
// The server starts in this thread
|
// The server starts in this thread
|
||||||
spdlog::info("Starting server");
|
spdlog::info("Starting server");
|
||||||
Simulators simulators;
|
Simulators simulators(port);
|
||||||
g_simulators = &simulators;
|
|
||||||
|
|
||||||
Websocket web_socket(
|
return a.exec();
|
||||||
9002, &g_out, &g_err, [](std::string message) { return message_parser(message); },
|
|
||||||
[]() { return g_simulators->changed_UI_items().dump(); });
|
|
||||||
g_web_socket = &web_socket;
|
|
||||||
|
|
||||||
// Start the message processor and broadcast processor in separate threads
|
|
||||||
std::thread message_processor_thread(std::bind(&Websocket::process_messages, &web_socket));
|
|
||||||
std::thread broadcast_processor_thred(std::bind(&Websocket::process_broadcast, &web_socket));
|
|
||||||
|
|
||||||
// Run the asio loop with the main thread
|
|
||||||
web_socket.run();
|
|
||||||
|
|
||||||
// Wait for the threads to finish (should never happen)
|
|
||||||
message_processor_thread.join();
|
|
||||||
broadcast_processor_thred.join();
|
|
||||||
}
|
}
|
||||||
+16
-18
@@ -1,15 +1,13 @@
|
|||||||
#include "message_parser.hpp"
|
#include "simulators.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <magic_enum.hpp>
|
#include <magic_enum.hpp>
|
||||||
|
|
||||||
extern Simulators *g_simulators;
|
QString Simulators::message_parser(QString message)
|
||||||
|
|
||||||
std::string message_parser(std::string message)
|
|
||||||
{
|
{
|
||||||
json j = json::parse(message);
|
json j = json::parse(message.toStdString());
|
||||||
if (j.contains("command"))
|
if (j.contains("command"))
|
||||||
{
|
{
|
||||||
return command_parser(j["command"]).dump();
|
return QString::fromStdString(command_parser(j["command"]).dump());
|
||||||
}
|
}
|
||||||
else if (j.contains("event"))
|
else if (j.contains("event"))
|
||||||
{
|
{
|
||||||
@@ -22,7 +20,7 @@ std::string message_parser(std::string message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
json command_parser(json command)
|
json Simulators::command_parser(json command)
|
||||||
{
|
{
|
||||||
json j = "{}"_json;
|
json j = "{}"_json;
|
||||||
try
|
try
|
||||||
@@ -35,27 +33,27 @@ json command_parser(json command)
|
|||||||
spdlog::info("Command {}: {}", type, std::string(command.at("id")));
|
spdlog::info("Command {}: {}", type, std::string(command.at("id")));
|
||||||
j["response"]["type"] = type;
|
j["response"]["type"] = type;
|
||||||
j["response"]["UI_item"] =
|
j["response"]["UI_item"] =
|
||||||
g_simulators->invoke_active_simulator()->get_UI_item(command.at("id"))->to_json();
|
invoke_active_simulator()->get_UI_item(command.at("id"))->to_json();
|
||||||
break;
|
break;
|
||||||
case Command::get_UI_elements:
|
case Command::get_UI_elements:
|
||||||
spdlog::info("Command {}", type);
|
spdlog::info("Command {}", type);
|
||||||
j["response"]["type"] = type;
|
j["response"]["type"] = type;
|
||||||
j["response"]["UI_items"] = g_simulators->invoke_active_simulator()->get_UI_items()["UI_items"];
|
j["response"]["UI_items"] = invoke_active_simulator()->get_UI_items()["UI_items"];
|
||||||
break;
|
break;
|
||||||
case Command::switch_simulator:
|
case Command::switch_simulator:
|
||||||
spdlog::info("Command {} to {}", type, std::string(command.at("name")));
|
spdlog::info("Command {} to {}", type, std::string(command.at("name")));
|
||||||
g_simulators->switch_simulator(command.at("name"));
|
switch_simulator(command.at("name"));
|
||||||
j["response"]["type"] = type;
|
j["response"]["type"] = type;
|
||||||
break;
|
break;
|
||||||
case Command::get_active_simulator_name:
|
case Command::get_active_simulator_name:
|
||||||
spdlog::info("Command {}", type);
|
spdlog::info("Command {}", type);
|
||||||
j["response"]["type"] = type;
|
j["response"]["type"] = type;
|
||||||
j["response"]["name"] = g_simulators->active_simulator_name();
|
j["response"]["name"] = active_simulator_name();
|
||||||
break;
|
break;
|
||||||
case Command::get_simulators:
|
case Command::get_simulators:
|
||||||
spdlog::info("Command {}", type);
|
spdlog::info("Command {}", type);
|
||||||
j["response"]["type"] = type;
|
j["response"]["type"] = type;
|
||||||
j["response"]["simulators"] = g_simulators->list_simulators();
|
j["response"]["simulators"] = list_simulators();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -69,13 +67,13 @@ json command_parser(json command)
|
|||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
void event_handler(json event)
|
void Simulators::event_handler(json event)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::string type = event.at("type");
|
std::string type = event.at("type");
|
||||||
Event e = magic_enum::enum_cast<Event>(type).value_or(Event::end);
|
Event e = magic_enum::enum_cast<Event>(type).value_or(Event::end);
|
||||||
if (g_simulators->invoke_active_simulator() == nullptr)
|
if (invoke_active_simulator() == nullptr)
|
||||||
{
|
{
|
||||||
spdlog::error("Event got called but there is no active simulator");
|
spdlog::error("Event got called but there is no active simulator");
|
||||||
return;
|
return;
|
||||||
@@ -85,26 +83,26 @@ void event_handler(json event)
|
|||||||
{
|
{
|
||||||
case Event::clicked: {
|
case Event::clicked: {
|
||||||
spdlog::debug("Event {}: {}", type, std::string(event.at("id")));
|
spdlog::debug("Event {}: {}", type, std::string(event.at("id")));
|
||||||
g_simulators->invoke_active_simulator()->get_UI_item(std::string(event.at("id")))->click();
|
invoke_active_simulator()->get_UI_item(std::string(event.at("id")))->click();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Event::value_changed: {
|
case Event::value_changed: {
|
||||||
spdlog::debug("Event {}: {} {}", type, std::string(event.at("id")), (double)(event["value"]));
|
spdlog::debug("Event {}: {} {}", type, std::string(event.at("id")), (double)(event["value"]));
|
||||||
g_simulators->invoke_active_simulator()
|
invoke_active_simulator()
|
||||||
->get_UI_item(std::string(event.at("id")))
|
->get_UI_item(std::string(event.at("id")))
|
||||||
->set_value((double)event.at("value"));
|
->set_value((double)event.at("value"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Event::text_changed: {
|
case Event::text_changed: {
|
||||||
spdlog::debug("Event {}: {} {}", type, std::string(event.at("id")), std::string(event.at("text")));
|
spdlog::debug("Event {}: {} {}", type, std::string(event.at("id")), std::string(event.at("text")));
|
||||||
g_simulators->invoke_active_simulator()
|
invoke_active_simulator()
|
||||||
->get_UI_item(std::string(event.at("id")))
|
->get_UI_item(std::string(event.at("id")))
|
||||||
->set_text(std::string(event.at("text")));
|
->set_text(std::string(event.at("text")));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Event::selected: {
|
case Event::selected: {
|
||||||
spdlog::debug("Event {}: {} {}", type, std::string(event.at("id")), std::string(event.at("selected")));
|
spdlog::debug("Event {}: {} {}", type, std::string(event.at("id")), std::string(event.at("selected")));
|
||||||
g_simulators->invoke_active_simulator()
|
invoke_active_simulator()
|
||||||
->get_UI_item(std::string(event.at("id")))
|
->get_UI_item(std::string(event.at("id")))
|
||||||
->set_selected(std::string(event.at("selected")));
|
->set_selected(std::string(event.at("selected")));
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "simulators.hpp"
|
|
||||||
|
|
||||||
enum class Command
|
|
||||||
{
|
|
||||||
get_UI_element,
|
|
||||||
get_UI_elements,
|
|
||||||
switch_simulator,
|
|
||||||
get_active_simulator_name,
|
|
||||||
get_simulators,
|
|
||||||
end,
|
|
||||||
begin = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Event
|
|
||||||
{
|
|
||||||
clicked,
|
|
||||||
value_changed,
|
|
||||||
text_changed,
|
|
||||||
selected,
|
|
||||||
ui_changed,
|
|
||||||
end,
|
|
||||||
begin = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string message_parser(std::string message);
|
|
||||||
json command_parser(json command);
|
|
||||||
void event_handler(json event);
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "simulator_base.hpp"
|
#include "simulator_base.hpp"
|
||||||
|
|
||||||
Simulator_base::Simulator_base(std::string name, std::chrono::milliseconds interval)
|
Simulator_base::Simulator_base(std::string name, std::chrono::milliseconds interval, QObject* parrent)
|
||||||
: m_name(name), m_timer([this] { timer(); }), m_interval(interval)
|
: QObject(parrent), m_name(name), m_timer([this] { timer(); }), m_interval(interval)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,6 +32,7 @@ void Simulator_base::add_UI_item(UI_item *item)
|
|||||||
{
|
{
|
||||||
throw std::runtime_error("UI item id " + item->id() + " is not unique");
|
throw std::runtime_error("UI item id " + item->id() + " is not unique");
|
||||||
}
|
}
|
||||||
|
connect(item, &UI_item::value_changed, this, [this]{emit sim_changed();});
|
||||||
m_UI_items_map[item->id()] = item;
|
m_UI_items_map[item->id()] = item;
|
||||||
m_UI_items.push_back(item);
|
m_UI_items.push_back(item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
#include "timer.hpp"
|
#include "timer.hpp"
|
||||||
|
|
||||||
class Simulator_base
|
class Simulator_base : public QObject
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Construct a new Simulator_base object
|
* @brief Construct a new Simulator_base object
|
||||||
@@ -14,7 +14,7 @@ class Simulator_base
|
|||||||
* @param name The name of the simulator
|
* @param name The name of the simulator
|
||||||
* @param interval The interval of the timer (default is 100ms)
|
* @param interval The interval of the timer (default is 100ms)
|
||||||
*/
|
*/
|
||||||
Simulator_base(std::string name, std::chrono::milliseconds interval = std::chrono::milliseconds(100));
|
Simulator_base(std::string name, std::chrono::milliseconds interval = std::chrono::milliseconds(100), QObject* parrent = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the name of the simulator
|
* @brief Returns the name of the simulator
|
||||||
@@ -82,6 +82,8 @@ class Simulator_base
|
|||||||
|
|
||||||
void shutdown();
|
void shutdown();
|
||||||
void reboot();
|
void reboot();
|
||||||
|
signals:
|
||||||
|
void sim_changed();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
|
|||||||
+22
-1
@@ -2,11 +2,26 @@
|
|||||||
#include "can_debugger.hpp"
|
#include "can_debugger.hpp"
|
||||||
#include "test_sim.hpp"
|
#include "test_sim.hpp"
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
Simulators::Simulators()
|
Simulators::Simulators(uint16_t port, QObject* parrent) :
|
||||||
|
QObject(parrent),
|
||||||
|
m_server(new Websocket(port, this))
|
||||||
{
|
{
|
||||||
|
qDebug() << port;
|
||||||
INSERT_SIMULATOR(Test_Sim);
|
INSERT_SIMULATOR(Test_Sim);
|
||||||
INSERT_SIMULATOR(Can_Debugger);
|
INSERT_SIMULATOR(Can_Debugger);
|
||||||
|
setup_connections();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Simulators::setup_connections()
|
||||||
|
{
|
||||||
|
connect(m_server, &Websocket::on_message, this, [this](QWebSocket* conn, QString message){
|
||||||
|
QString response = message_parser(message);
|
||||||
|
if (response.isEmpty() || response == "{}")
|
||||||
|
return;
|
||||||
|
m_server->send(conn, response);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Simulators::active_simulator_name() const
|
std::string Simulators::active_simulator_name() const
|
||||||
@@ -59,7 +74,13 @@ void Simulators::switch_simulator(std::string name)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->stop();
|
||||||
|
if (!this->m_current_simulator.empty())
|
||||||
|
{
|
||||||
|
disconnect(m_simulators.at(m_current_simulator).get());
|
||||||
|
}
|
||||||
this->m_current_simulator = name;
|
this->m_current_simulator = name;
|
||||||
|
connect(m_simulators.at(m_current_simulator).get(), &Simulator_base::sim_changed, this, [this]{m_server->broadcast(QString::fromStdString(changed_UI_items().dump()));});
|
||||||
this->run();
|
this->run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+33
-2
@@ -3,14 +3,39 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
#include "websocket.hpp"
|
||||||
#include "simulator_base.hpp"
|
#include "simulator_base.hpp"
|
||||||
|
|
||||||
#define INSERT_SIMULATOR(type) m_simulators.insert(std::make_pair(type().name(), std::make_unique<type>()));
|
#define INSERT_SIMULATOR(type) m_simulators.insert(std::make_pair(type().name(), std::make_unique<type>()));
|
||||||
|
|
||||||
class Simulators
|
class Simulators : public QObject
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Simulators();
|
enum class Command
|
||||||
|
{
|
||||||
|
get_UI_element,
|
||||||
|
get_UI_elements,
|
||||||
|
switch_simulator,
|
||||||
|
get_active_simulator_name,
|
||||||
|
get_simulators,
|
||||||
|
end,
|
||||||
|
begin = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Event
|
||||||
|
{
|
||||||
|
clicked,
|
||||||
|
value_changed,
|
||||||
|
text_changed,
|
||||||
|
selected,
|
||||||
|
ui_changed,
|
||||||
|
end,
|
||||||
|
begin = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
Simulators(uint16_t port, QObject *parent = nullptr);
|
||||||
|
void setup_connections();
|
||||||
std::string active_simulator_name() const;
|
std::string active_simulator_name() const;
|
||||||
void run();
|
void run();
|
||||||
void stop();
|
void stop();
|
||||||
@@ -19,7 +44,13 @@ class Simulators
|
|||||||
Simulator_base *invoke_active_simulator();
|
Simulator_base *invoke_active_simulator();
|
||||||
json changed_UI_items();
|
json changed_UI_items();
|
||||||
|
|
||||||
|
//parsing of websocket messages
|
||||||
|
QString message_parser(QString message);
|
||||||
|
json command_parser(json command);
|
||||||
|
void event_handler(json event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Websocket *m_server;
|
||||||
std::map<std::string, std::unique_ptr<Simulator_base>> m_simulators;
|
std::map<std::string, std::unique_ptr<Simulator_base>> m_simulators;
|
||||||
std::string m_current_simulator = "";
|
std::string m_current_simulator = "";
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "simulator_base.hpp"
|
#include "simulator_base.hpp"
|
||||||
|
|
||||||
class Can_Debugger : public Simulator_base {
|
class Can_Debugger : public Simulator_base {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Can_Debugger();
|
Can_Debugger();
|
||||||
void timer() override;
|
void timer() override;
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#include "test_sim.hpp"
|
#include "test_sim.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
Test_Sim::Test_Sim() :
|
Test_Sim::Test_Sim(QObject* parrent) :
|
||||||
Simulator_base("Test_Sim", std::chrono::milliseconds(1000)),
|
Simulator_base("Test_Sim", std::chrono::milliseconds(1000), parrent),
|
||||||
m_button("button", "Off", Color(Color::White), Color(Color::Red), [this](std::string id) { button_clicked(id); }),
|
m_button("button", "Off", Color(Color::White), Color(Color::Red)),
|
||||||
m_combobox("combobox", "Combobox", Color(Color::White), Color(Color::Black), {"Option 1", "Option 2", "Option 3"}, 0, [](std::string id, std::string selected) { spdlog::info("Combobox {} selected {}", id, selected); }),
|
m_combobox("combobox", "Combobox", Color(Color::White), Color(Color::Black), {"Option 1", "Option 2", "Option 3"}, 0),
|
||||||
m_label("label", "Label", Color(Color::White), Color(Color::Black)),
|
m_label("label", "Label", Color(Color::White), Color(Color::Black)),
|
||||||
m_checkbox("checkbox", "Checkbox", Color(Color::White), Color(Color::Black), {"Option 1", "Option 2", "Option 3"}, [](std::string id, std::vector<std::string> selected) { spdlog::info("Checkbox {} selected {}", id, (selected.size() > 0 ? selected[0] : "")); }),
|
m_checkbox("checkbox", "Checkbox", Color(Color::White), Color(Color::Black), {"Option 1", "Option 2", "Option 3"}),
|
||||||
m_slider("slider", "Slider", Color(Color::White), Color(Color::Black), 0, 100, 0, [this](std::string id, double value) { slider_changed(id, value); }),
|
m_slider("slider", "Slider", Color(Color::White), Color(Color::Black), 0, 100, 0),
|
||||||
m_dial("dial", "Dial", Color(Color::White), Color(Color::Black), 0, 100, 0),
|
m_dial("dial", "Dial", Color(Color::White), Color(Color::Black), 0, 100, 0),
|
||||||
m_thermo("thermo", "Thermo", Color(Color::White), Color(Color::Black), 0, 100, 0),
|
m_thermo("thermo", "Thermo", Color(Color::White), Color(Color::Black), 0, 100, 0),
|
||||||
m_led("led", "Led", Color(Color::White), Color(Color::Black), Color(Color::Red))
|
m_led("led", "Led", Color(Color::White), Color(Color::Black), Color(Color::Red))
|
||||||
@@ -27,6 +27,9 @@ m_led("led", "Led", Color(Color::White), Color(Color::Black), Color(Color::Red))
|
|||||||
this->add_UI_item(&this->m_dial);
|
this->add_UI_item(&this->m_dial);
|
||||||
this->add_UI_item(&this->m_thermo);
|
this->add_UI_item(&this->m_thermo);
|
||||||
this->add_UI_item(&this->m_led);
|
this->add_UI_item(&this->m_led);
|
||||||
|
|
||||||
|
QObject::connect(&m_button, &UI_button::on_click, [this](std::string id) { button_clicked(id); });
|
||||||
|
QObject::connect(&m_slider, &UI_slider::on_change, [this](std::string id, double value) { slider_changed(id, value); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Test_Sim::timer()
|
void Test_Sim::timer()
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
#include "simulator_base.hpp"
|
#include "simulator_base.hpp"
|
||||||
|
|
||||||
class Test_Sim : public Simulator_base {
|
class Test_Sim : public Simulator_base {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Test_Sim();
|
Test_Sim(QObject* parrent = nullptr);
|
||||||
void timer() override;
|
void timer() override;
|
||||||
void run_at_startup() override;
|
void run_at_startup() override;
|
||||||
private:
|
private:
|
||||||
|
|||||||
+53
-134
@@ -1,150 +1,69 @@
|
|||||||
#include "websocket.hpp"
|
#include "websocket.hpp"
|
||||||
#include "spdlog/spdlog.h"
|
#include "QtWebSockets/qwebsocketserver.h"
|
||||||
|
#include "QtWebSockets/qwebsocket.h"
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
Websocket::Websocket(uint16_t port, std::ostream *out, std::ostream *err,
|
Websocket::Websocket(uint16_t port, QObject *parent) :
|
||||||
std::function<std::string(std::string)> on_message, std::function<std::string()> on_update)
|
QObject(parent),
|
||||||
: m_on_message(on_message), m_on_update(on_update), m_port(port)
|
m_pWebSocketServer(new QWebSocketServer(QStringLiteral("sim_us Server"),
|
||||||
|
QWebSocketServer::NonSecureMode, this))
|
||||||
{
|
{
|
||||||
// Set logging settings
|
if (m_pWebSocketServer->listen(QHostAddress::Any, port)) {
|
||||||
m_server.get_alog().set_custom(out != &std::cout);
|
qDebug() << "Echoserver listening on port" << port;
|
||||||
m_server.get_elog().set_custom(err != &std::cerr);
|
connect(m_pWebSocketServer, &QWebSocketServer::newConnection,
|
||||||
m_server.get_alog().set_ostream(out);
|
this, &Websocket::onNewConnection);
|
||||||
m_server.get_elog().set_ostream(err);
|
connect(m_pWebSocketServer, &QWebSocketServer::closed, this, &Websocket::closed);
|
||||||
m_server.set_access_channels(websocketpp::log::alevel::connect + websocketpp::log::alevel::disconnect);
|
|
||||||
m_server.clear_access_channels(websocketpp::log::alevel::frame_payload + websocketpp::log::alevel::frame_header +
|
|
||||||
websocketpp::log::alevel::control);
|
|
||||||
|
|
||||||
// Initialize Asio
|
|
||||||
m_server.init_asio();
|
|
||||||
|
|
||||||
// Register our message handler
|
|
||||||
m_server.set_open_handler(std::bind(&Websocket::on_open, this, ::_1));
|
|
||||||
m_server.set_close_handler(std::bind(&Websocket::on_close, this, ::_1));
|
|
||||||
m_server.set_message_handler(std::bind(&Websocket::on_message, this, ::_1, ::_2));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Websocket::run()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// listen on specified port
|
|
||||||
m_server.listen(m_port);
|
|
||||||
// Start the server accept loop
|
|
||||||
m_server.start_accept();
|
|
||||||
// Start the ASIO io_service run loop
|
|
||||||
m_server.run();
|
|
||||||
}
|
|
||||||
catch (websocketpp::exception const &e)
|
|
||||||
{
|
|
||||||
spdlog::critical("{}", e.what());
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
spdlog::critical("other exception");
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Websocket::stop()
|
Websocket::~Websocket()
|
||||||
{
|
{
|
||||||
m_server.stop_listening();
|
m_pWebSocketServer->close();
|
||||||
m_server.stop();
|
qDeleteAll(m_clients.begin(), m_clients.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Websocket::on_open(websocketpp::connection_hdl hdl)
|
void Websocket::broadcast(QString message)
|
||||||
{
|
{
|
||||||
{
|
foreach (QWebSocket* conn, m_clients) {
|
||||||
std::lock_guard<std::mutex> guard(m_action_lock);
|
conn->sendTextMessage(message);
|
||||||
m_actions.push(action(SUBSCRIBE, hdl));
|
|
||||||
}
|
|
||||||
m_action_cond.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Websocket::on_close(websocketpp::connection_hdl hdl)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> guard(m_action_lock);
|
|
||||||
m_actions.push(action(UNSUBSCRIBE, hdl));
|
|
||||||
}
|
|
||||||
m_action_cond.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Websocket::on_message(websocketpp::connection_hdl hdl, Server::message_ptr msg)
|
|
||||||
{
|
|
||||||
// return pong
|
|
||||||
if (msg->get_opcode() == websocketpp::frame::opcode::PING)
|
|
||||||
{
|
|
||||||
m_server.send(hdl, msg->get_payload(), websocketpp::frame::opcode::PONG);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// queue message up for sending by processing thread
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> guard(m_action_lock);
|
|
||||||
m_actions.push(action(MESSAGE, hdl, msg));
|
|
||||||
}
|
|
||||||
m_action_cond.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Websocket::process_messages()
|
|
||||||
{
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(m_action_lock);
|
|
||||||
|
|
||||||
while (m_actions.empty())
|
|
||||||
{
|
|
||||||
m_action_cond.wait(lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
action a = m_actions.front();
|
|
||||||
m_actions.pop();
|
|
||||||
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
switch (a.type)
|
|
||||||
{
|
|
||||||
case SUBSCRIBE: {
|
|
||||||
std::lock_guard<std::mutex> guard(m_connection_lock);
|
|
||||||
m_connections.insert(a.hdl);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case UNSUBSCRIBE: {
|
|
||||||
std::lock_guard<std::mutex> guard(m_connection_lock);
|
|
||||||
m_connections.erase(a.hdl);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MESSAGE: {
|
|
||||||
std::string response = m_on_message(a.msg->get_payload());
|
|
||||||
if (response.empty() || response == "{}")
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
m_server.send(a.hdl, response, websocketpp::frame::opcode::TEXT);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Websocket::process_broadcast()
|
void Websocket::send(QWebSocket* conn, QString message)
|
||||||
{
|
{
|
||||||
while (1)
|
conn->sendTextMessage(message);
|
||||||
{
|
}
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
||||||
std::string update = m_on_update();
|
void Websocket::onNewConnection()
|
||||||
if (update.empty() || update == "{}")
|
{
|
||||||
{
|
QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
|
||||||
continue;
|
|
||||||
}
|
connect(pSocket, &QWebSocket::textMessageReceived, this, &Websocket::processTextMessage);
|
||||||
{
|
connect(pSocket, &QWebSocket::binaryMessageReceived, this, &Websocket::processBinaryMessage);
|
||||||
std::lock_guard<std::mutex> guard(m_connection_lock);
|
connect(pSocket, &QWebSocket::disconnected, this, &Websocket::socketDisconnected);
|
||||||
for (auto it : m_connections)
|
|
||||||
{
|
m_clients << pSocket;
|
||||||
m_server.send(it, update, websocketpp::frame::opcode::TEXT);
|
}
|
||||||
}
|
|
||||||
}
|
void Websocket::processTextMessage(QString message)
|
||||||
|
{
|
||||||
|
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
|
||||||
|
qDebug() << "Message received:" << message;
|
||||||
|
emit on_message(pClient, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Websocket::processBinaryMessage(QByteArray message)
|
||||||
|
{
|
||||||
|
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
|
||||||
|
qDebug() << "Binary Message received:" << message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Websocket::socketDisconnected()
|
||||||
|
{
|
||||||
|
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
|
||||||
|
qDebug() << "socketDisconnected:" << pClient;
|
||||||
|
if (pClient) {
|
||||||
|
m_clients.removeAll(pClient);
|
||||||
|
pClient->deleteLater();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+23
-59
@@ -1,69 +1,33 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
#include <QtCore/QObject>
|
||||||
#include <set>
|
#include <QtCore/QList>
|
||||||
|
#include <QtCore/QByteArray>
|
||||||
|
|
||||||
#include <websocketpp/config/asio_no_tls.hpp>
|
QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
|
||||||
#include <websocketpp/server.hpp>
|
QT_FORWARD_DECLARE_CLASS(QWebSocket)
|
||||||
|
|
||||||
typedef websocketpp::server<websocketpp::config::asio> Server;
|
class Websocket : public QObject
|
||||||
|
|
||||||
using websocketpp::lib::placeholders::_1;
|
|
||||||
using websocketpp::lib::placeholders::_2;
|
|
||||||
|
|
||||||
/* on_open insert connection_hdl into channel
|
|
||||||
* on_close remove connection_hdl from channel
|
|
||||||
* on_message queue send to all channels
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum action_type
|
|
||||||
{
|
{
|
||||||
SUBSCRIBE,
|
Q_OBJECT
|
||||||
UNSUBSCRIBE,
|
|
||||||
MESSAGE,
|
|
||||||
BROADCAST
|
|
||||||
};
|
|
||||||
|
|
||||||
struct action
|
|
||||||
{
|
|
||||||
action(action_type t, websocketpp::connection_hdl h) : type(t), hdl(h)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
action(action_type t, websocketpp::connection_hdl h, Server::message_ptr m) : type(t), hdl(h), msg(m)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
action_type type;
|
|
||||||
websocketpp::connection_hdl hdl;
|
|
||||||
Server::message_ptr msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Websocket
|
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
Websocket(uint16_t port, std::ostream *out, std::ostream *err, std::function<std::string(std::string)> on_message,
|
Websocket(uint16_t port, QObject *parent = nullptr);
|
||||||
std::function<std::string()> on_update);
|
~Websocket();
|
||||||
void run();
|
|
||||||
void stop();
|
void broadcast(QString message);
|
||||||
void process_messages();
|
void send(QWebSocket* conn, QString message);
|
||||||
void process_broadcast();
|
signals:
|
||||||
|
void on_message(QWebSocket* conn, QString message);
|
||||||
|
void closed();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onNewConnection();
|
||||||
|
void processTextMessage(QString message);
|
||||||
|
void processBinaryMessage(QByteArray message);
|
||||||
|
void socketDisconnected();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void on_open(websocketpp::connection_hdl hdl);
|
QWebSocketServer *m_pWebSocketServer;
|
||||||
void on_close(websocketpp::connection_hdl hdl);
|
QList<QWebSocket *> m_clients;
|
||||||
void on_message(websocketpp::connection_hdl hdl, Server::message_ptr msg);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::function<std::string(std::string)> m_on_message;
|
|
||||||
std::function<std::string()> m_on_update;
|
|
||||||
Server m_server;
|
|
||||||
uint16_t m_port;
|
|
||||||
typedef std::set<websocketpp::connection_hdl, std::owner_less<websocketpp::connection_hdl>> con_list;
|
|
||||||
con_list m_connections;
|
|
||||||
|
|
||||||
std::queue<action> m_actions;
|
|
||||||
|
|
||||||
std::mutex m_action_lock;
|
|
||||||
std::mutex m_connection_lock;
|
|
||||||
std::condition_variable m_action_cond;
|
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user