factory idea for wasm

cleanup
remove unused defines
This commit is contained in:
2026-04-12 13:42:02 +02:00
parent 59f7680f94
commit 8ce89a3076
16 changed files with 113 additions and 186 deletions
+12 -83
View File
@@ -4,17 +4,26 @@ find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Svg WebSockets)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR})
file(GLOB_RECURSE ui "ui/*") file(GLOB_RECURSE ui "ui/*")
file(GLOB_RECURSE sims "simulators/*")
set(PROJECT_SOURCES set(PROJECT_SOURCES
${ui}
${sims}
IterableEnum.hpp IterableEnum.hpp
main.cpp main.cpp
mainwindow.cpp mainwindow.cpp
mainwindow.hpp mainwindow.hpp
mainwindow.ui mainwindow.ui
factory.hpp
helpers.cpp
helpers.hpp
ui_base.cpp
ui_base.hpp
web_socket_wrapper.cpp
web_socket_wrapper.hpp
) )
qt_add_executable(unisim_client qt_add_executable(unisim_client
MANUAL_FINALIZATION
${PROJECT_SOURCES} ${PROJECT_SOURCES}
) )
@@ -29,11 +38,12 @@ set_target_properties(
target_include_directories(unisim_client target_include_directories(unisim_client
PUBLIC PUBLIC
${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/ui
${CMAKE_CURRENT_LIST_DIR}/simulators ${CMAKE_CURRENT_LIST_DIR}/simulators
${PROJECT_BINARY_DIR}/ ${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 client_common) 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)
include(GNUInstallDirs) include(GNUInstallDirs)
install(TARGETS unisim_client install(TARGETS unisim_client
@@ -41,84 +51,3 @@ install(TARGETS unisim_client
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
) )
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(unisim_client)
endif()
add_library(client_common SHARED)
target_sources(client_common
PRIVATE
${ui}
helpers.cpp
helpers.hpp
ui_base.cpp
ui_base.hpp
web_socket_wrapper.cpp
web_socket_wrapper.hpp
)
target_compile_definitions(client_common PRIVATE
INTERNAL
)
target_link_libraries(client_common
PUBLIC
qwt Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::WebSockets magic_enum::magic_enum nlohmann_json::nlohmann_json UI_enum
)
set_target_properties(
client_common
PROPERTIES
AUTOMOC ON
AUTORCC ON
AUTOUIC ON
)
target_include_directories(client_common
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/ui
${PROJECT_BINARY_DIR}
)
add_custom_command(TARGET client_common POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:client_common>
$<TARGET_FILE_DIR:unisim_client>)
add_custom_target(copy_qwt_to_unisim
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:qwt>
$<TARGET_FILE_DIR:unisim_client>
COMMENT "Copying qwt → unisim_client output dir"
VERBATIM
)
add_dependencies(unisim_client copy_qwt_to_unisim)
if (NOT EMSCRIPTEN)
file(GLOB_RECURSE sims "simulators/*.cpp")
# Loop through each .cpp file and create a library for it
foreach(sim ${sims})
# Extract the base name of the file (without the directory and extension)
get_filename_component(LIB_NAME ${sim} NAME_WE)
# Create a library for each .cpp file
add_library(ui_${LIB_NAME} SHARED ${CMAKE_CURRENT_SOURCE_DIR}/simulators/${LIB_NAME}.hpp ${CMAKE_CURRENT_SOURCE_DIR}/simulators/${LIB_NAME}.cpp ${CMAKE_CURRENT_SOURCE_DIR}/simulators/${LIB_NAME}.ui)
target_link_libraries(ui_${LIB_NAME} PUBLIC Qt${QT_VERSION_MAJOR}::Widgets client_common)
target_include_directories(ui_${LIB_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/ui ${PROJECT_BINARY_DIR}/)
set_target_properties(
ui_${LIB_NAME}
PROPERTIES
AUTOUIC ON
AUTOMOC ON
AUTORCC ON
)
add_custom_command(TARGET ui_${LIB_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:ui_${LIB_NAME}>
$<TARGET_FILE_DIR:unisim_client>)
endforeach()
else()
file(GLOB_RECURSE sims "simulators/*")
endif()
+57
View File
@@ -0,0 +1,57 @@
#pragma once
#include "ui_base.hpp"
#include <QMap>
#include <QObject>
#include <QString>
#include <functional>
class UIFactory
{
public:
using Creator = std::function<UI_base *(Web_socket_wrapper *web_socket, QWidget *)>;
static UIFactory &instance()
{
static UIFactory f;
return f;
}
bool registerType(const QString &key, Creator creator)
{
if (m_creators.contains(key))
return false;
m_creators.insert(key, creator);
return true;
}
UI_base *create(const QString &key, Web_socket_wrapper *w, QWidget *parent = nullptr) const
{
auto it = m_creators.constFind(key);
if (it == m_creators.cend())
return nullptr;
return it.value()(w, parent);
}
QStringList keys() const
{
return m_creators.keys();
}
private:
QMap<QString, Creator> m_creators;
};
#define REGISTER_UI(TYPE) \
namespace \
{ \
struct Register##TYPE \
{ \
Register##TYPE() \
{ \
UIFactory::instance().registerType(TYPE::name(), \
[](Web_socket_wrapper *w, QWidget *p) { return new TYPE(w, p); }); \
} \
}; \
static Register##TYPE register_##TYPE; \
}
+8 -22
View File
@@ -1,4 +1,5 @@
#include "mainwindow.hpp" #include "mainwindow.hpp"
#include "factory.hpp"
#include "ui_base.hpp" #include "ui_base.hpp"
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include "web_socket_wrapper.hpp" #include "web_socket_wrapper.hpp"
@@ -9,8 +10,6 @@
#include <magic_enum/magic_enum.hpp> #include <magic_enum/magic_enum.hpp>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
typedef UI_base *(*Get_UI)(Web_socket_wrapper *, QWidget *);
MainWindow::MainWindow(QUrl ws_url, QString sim, QWidget *parent) MainWindow::MainWindow(QUrl ws_url, QString sim, QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow), m_error(new QMessageBox()), : QMainWindow(parent), ui(new Ui::MainWindow), m_error(new QMessageBox()),
m_web_socket(new Web_socket_wrapper(ws_url)) m_web_socket(new Web_socket_wrapper(ws_url))
@@ -23,34 +22,20 @@ MainWindow::MainWindow(QUrl ws_url, QString sim, QWidget *parent)
(spdlog::level::level_enum)level, msg.toStdString()); (spdlog::level::level_enum)level, msg.toStdString());
}); });
QDirIterator it(QCoreApplication::applicationDirPath(), QStringList() << "*libui_*.so" << "*libui_*.dll", for (const QString &name : UIFactory::instance().keys())
QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext())
{ {
QLibrary lib; if (auto *w = UIFactory::instance().create(name, m_web_socket.get(), this))
lib.setFileName(it.next());
lib.load();
auto loaded_ui = Get_UI(lib.resolve("get_ui"));
if (loaded_ui == nullptr)
{ {
SPDLOG_INFO("{} NOT FOUND", lib.fileName().toStdString()); w->set_name(name);
lib.unload(); m_sims.insert(std::make_pair(name, w));
continue; connect(w, &UI_base::log_signal, this,
}
auto widget = loaded_ui(m_web_socket.get(), this);
if (widget == nullptr)
{
lib.unload();
continue;
}
m_sims.insert(std::make_pair(widget->name(), widget));
connect(widget, &UI_base::log_signal, this,
[](const char *filename_in, int line_in, const char *funcname_in, int level, QString msg) { [](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)) 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::default_logger_raw()->log(spdlog::source_loc{filename_in, line_in, funcname_in},
(spdlog::level::level_enum)level, msg.toStdString()); (spdlog::level::level_enum)level, msg.toStdString());
}); });
} }
}
// Insert debug sims here // Insert debug sims here
// INSERT_SIMULATOR(SIM_NAME); // INSERT_SIMULATOR(SIM_NAME);
@@ -103,6 +88,7 @@ void MainWindow::pase_sim_names(json &sims)
{ {
for (json &item : sims) for (json &item : sims)
{ {
if (m_sims.contains(QString::fromStdString(item)))
ui->comboBox->addItem(QString::fromStdString(item)); ui->comboBox->addItem(QString::fromStdString(item));
} }
+3 -2
View File
@@ -1,10 +1,11 @@
#include "can_debugger.hpp" #include "can_debugger.hpp"
#include "factory.hpp"
#include "ui_can_debugger.h" #include "ui_can_debugger.h"
EXPORT_UI(Can_Debugger); REGISTER_UI(Can_Debugger);
Can_Debugger::Can_Debugger(Web_socket_wrapper *web_socket, QWidget *parent) Can_Debugger::Can_Debugger(Web_socket_wrapper *web_socket, QWidget *parent)
: UI_base("Can Debugger", web_socket, parent), ui(new Ui::Can_Debugger) : UI_base(web_socket, parent), ui(new Ui::Can_Debugger)
{ {
ui->setupUi(this); ui->setupUi(this);
+4
View File
@@ -13,6 +13,10 @@ class Can_Debugger : public UI_base
public: public:
explicit Can_Debugger(Web_socket_wrapper *web_socket = nullptr, QWidget *parent = nullptr); explicit Can_Debugger(Web_socket_wrapper *web_socket = nullptr, QWidget *parent = nullptr);
~Can_Debugger(); ~Can_Debugger();
static QString name()
{
return "Can Debugger";
};
private: private:
Ui::Can_Debugger *ui; Ui::Can_Debugger *ui;
+3 -3
View File
@@ -1,10 +1,10 @@
#include "test.hpp" #include "test.hpp"
#include "factory.hpp"
#include "ui_test.h" #include "ui_test.h"
EXPORT_UI(Test_Sim); REGISTER_UI(Test_Sim);
Test_Sim::Test_Sim(Web_socket_wrapper *web_socket, QWidget *parent) Test_Sim::Test_Sim(Web_socket_wrapper *web_socket, QWidget *parent) : UI_base(web_socket, parent), ui(new Ui::Test_Sim)
: UI_base("Test Sim", web_socket, parent), ui(new Ui::Test_Sim)
{ {
ui->setupUi(this); ui->setupUi(this);
+5
View File
@@ -14,6 +14,11 @@ class Test_Sim : public UI_base
explicit Test_Sim(Web_socket_wrapper *web_socket = nullptr, QWidget *parent = nullptr); explicit Test_Sim(Web_socket_wrapper *web_socket = nullptr, QWidget *parent = nullptr);
~Test_Sim(); ~Test_Sim();
static QString name()
{
return "Test Sim";
};
QLabel *id_to_label(QWidget *widget) override; QLabel *id_to_label(QWidget *widget) override;
private: private:
+1 -7
View File
@@ -2,17 +2,11 @@
#include <QRadioButton> #include <QRadioButton>
#include <QVBoxLayout> #include <QVBoxLayout>
#ifdef INTERNAL
#define EXPORT Q_DECL_EXPORT
#else
#define EXPORT Q_DECL_IMPORT
#endif
/** /**
* @brief Class representing a better radiobutton group * @brief Class representing a better radiobutton group
* *
*/ */
class EXPORT Better_Radiobutton : public QWidget class Better_Radiobutton : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
+1 -7
View File
@@ -2,12 +2,6 @@
#include "hex_spinbox.hpp" #include "hex_spinbox.hpp"
#include <QWidget> #include <QWidget>
#ifdef INTERNAL
#define EXPORT Q_DECL_EXPORT
#else
#define EXPORT Q_DECL_IMPORT
#endif
namespace Ui namespace Ui
{ {
class Can_Transceive; class Can_Transceive;
@@ -17,7 +11,7 @@ class Can_Transceive;
* @brief Class representing a CAN transceive UI component * @brief Class representing a CAN transceive UI component
* *
*/ */
class EXPORT Can_Transceive : public QWidget class Can_Transceive : public QWidget
{ {
Q_OBJECT Q_OBJECT
+1 -7
View File
@@ -3,19 +3,13 @@
#include <QRegularExpressionValidator> #include <QRegularExpressionValidator>
#include <QSpinBox> #include <QSpinBox>
#ifdef INTERNAL
#define EXPORT Q_DECL_EXPORT
#else
#define EXPORT Q_DECL_IMPORT
#endif
/** /**
* @brief Class representing a hexadecimal spin box * @brief Class representing a hexadecimal spin box
* @note Since QSpinBox uses int as the storage type, the effective editing range * @note Since QSpinBox uses int as the storage type, the effective editing range
* is +/- 0x7FFF FFFF, so it can't handle a full unsigned int. * is +/- 0x7FFF FFFF, so it can't handle a full unsigned int.
* QDoubleSpinBox would be a more suitable base class if a wider range is needed. * QDoubleSpinBox would be a more suitable base class if a wider range is needed.
*/ */
class EXPORT HexSpinBox : public QSpinBox class HexSpinBox : public QSpinBox
{ {
Q_OBJECT Q_OBJECT
+1 -7
View File
@@ -1,17 +1,11 @@
#pragma once #pragma once
#include "QPushButton" #include "QPushButton"
#ifdef INTERNAL
#define EXPORT Q_DECL_EXPORT
#else
#define EXPORT Q_DECL_IMPORT
#endif
/** /**
* @brief Class representing an LED widget * @brief Class representing an LED widget
* *
*/ */
class EXPORT Led : public QPushButton class Led : public QPushButton
{ {
Q_OBJECT Q_OBJECT
public: public:
+1 -7
View File
@@ -4,17 +4,11 @@
#include <qwt_plot_curve.h> #include <qwt_plot_curve.h>
#include <qwt_text.h> #include <qwt_text.h>
#ifdef INTERNAL
#define EXPORT Q_DECL_EXPORT
#else
#define EXPORT Q_DECL_IMPORT
#endif
/** /**
* @brief Class wrapping a QwtPlot for plotting data * @brief Class wrapping a QwtPlot for plotting data
* *
*/ */
class EXPORT Plot_wrapper : public QwtPlot class Plot_wrapper : public QwtPlot
{ {
Q_OBJECT Q_OBJECT
public: public:
+7 -8
View File
@@ -7,9 +7,8 @@
#include <QMessageBox> #include <QMessageBox>
#include <magic_enum/magic_enum.hpp> #include <magic_enum/magic_enum.hpp>
UI_base::UI_base(QString name, Web_socket_wrapper *web_socket, QWidget *parent) 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), : QMainWindow{parent}, m_timer_update(new QTimer()), m_error(new QMessageBox(this)), m_web_socket(web_socket)
m_name(name)
{ {
this->setWindowState(Qt::WindowMaximized); this->setWindowState(Qt::WindowMaximized);
m_ui_lookup.reserve(40); m_ui_lookup.reserve(40);
@@ -760,16 +759,16 @@ UI_base::UI_base(QString name, Web_socket_wrapper *web_socket, QWidget *parent)
}); });
} }
void UI_base::set_name(QString name)
{
m_name = name;
}
QWidget *UI_base::id_to_ui(size_t id) QWidget *UI_base::id_to_ui(size_t id)
{ {
return m_ui_lookup.at(id); return m_ui_lookup.at(id);
} }
QString UI_base::name() const
{
return m_name;
}
void UI_base::showEvent(QShowEvent *event) void UI_base::showEvent(QShowEvent *event)
{ {
QWidget::showEvent(event); QWidget::showEvent(event);
+3 -20
View File
@@ -5,12 +5,6 @@
#include <functional> #include <functional>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#ifdef INTERNAL
#define EXPORT Q_DECL_EXPORT
#else
#define EXPORT Q_DECL_IMPORT
#endif
Q_FORWARD_DECLARE_OBJC_CLASS(Web_socket_wrapper); Q_FORWARD_DECLARE_OBJC_CLASS(Web_socket_wrapper);
Q_FORWARD_DECLARE_OBJC_CLASS(QTimer); Q_FORWARD_DECLARE_OBJC_CLASS(QTimer);
Q_FORWARD_DECLARE_OBJC_CLASS(QLabel); Q_FORWARD_DECLARE_OBJC_CLASS(QLabel);
@@ -19,11 +13,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QMessageBox);
using json = nlohmann::json; using json = nlohmann::json;
#define PUSH_UI_ITEM(item) push_ui_item(ui->item) #define PUSH_UI_ITEM(item) push_ui_item(ui->item)
#define EXPORT_UI(client) \
extern "C" Q_DECL_EXPORT UI_base *get_ui(Web_socket_wrapper *api, QWidget *parent) \
{ \
return new client(api, parent); \
}
#define LOG_SRC_LOC(level, msg) emit log_signal(__FILE__, __LINE__, __FUNCTION__, (int)(level), (msg)) #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_TRACE(msg) LOG_SRC_LOC(Log_level_enum::trace, msg)
@@ -36,7 +25,7 @@ using json = nlohmann::json;
/** /**
* @brief Base class for client UIs * @brief Base class for client UIs
*/ */
class EXPORT UI_base : public QMainWindow class UI_base : public QMainWindow
{ {
Q_OBJECT Q_OBJECT
public: public:
@@ -58,13 +47,8 @@ class EXPORT UI_base : public QMainWindow
* @param api The weboscket connection to the server API * @param api The weboscket connection to the server API
* @param parent The parent widget * @param parent The parent widget
*/ */
explicit UI_base(QString name, Web_socket_wrapper *api, QWidget *parent = nullptr); explicit UI_base(Web_socket_wrapper *api, QWidget *parent = nullptr);
/** void set_name(QString name);
* @brief Get the name of the simulator
*
* @return QString The name of the simulator
*/
QString name() const;
/** /**
* @brief Get the UI element by its ID * @brief Get the UI element by its ID
* *
@@ -216,7 +200,6 @@ class EXPORT UI_base : public QMainWindow
private: private:
Web_socket_wrapper *m_web_socket; Web_socket_wrapper *m_web_socket;
QString m_name; QString m_name;
QTimer *m_timer_update; QTimer *m_timer_update;
uint32_t m_refresh_rate; uint32_t m_refresh_rate;
QMessageBox *m_error; QMessageBox *m_error;
+1 -7
View File
@@ -2,12 +2,6 @@
#include <QObject> #include <QObject>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#ifdef INTERNAL
#define EXPORT Q_DECL_EXPORT
#else
#define EXPORT Q_DECL_IMPORT
#endif
Q_FORWARD_DECLARE_OBJC_CLASS(QWebSocket); Q_FORWARD_DECLARE_OBJC_CLASS(QWebSocket);
Q_FORWARD_DECLARE_OBJC_CLASS(QTimer); Q_FORWARD_DECLARE_OBJC_CLASS(QTimer);
using json = nlohmann::json; using json = nlohmann::json;
@@ -16,7 +10,7 @@ using json = nlohmann::json;
* @brief Class wrapping a WebSocket connection * @brief Class wrapping a WebSocket connection
* *
*/ */
class EXPORT Web_socket_wrapper : public QObject class Web_socket_wrapper : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
-1
View File
@@ -1,4 +1,3 @@
set(QWT_BUILD_SHARED ON)
set(COLOR_BUILD_PIC ON) set(COLOR_BUILD_PIC ON)
set(SPDLOG_BUILD_PIC ON) set(SPDLOG_BUILD_PIC ON)
add_subdirectory(color) add_subdirectory(color)