From 8ce89a3076e59aa1d58817cd696987d2bf521934 Mon Sep 17 00:00:00 2001 From: Sander Speetjens Date: Thu, 19 Feb 2026 22:27:01 +0100 Subject: [PATCH] factory idea for wasm cleanup remove unused defines --- client/CMakeLists.txt | 95 ++++-------------------------- client/factory.hpp | 57 ++++++++++++++++++ client/mainwindow.cpp | 40 ++++--------- client/simulators/can_debugger.cpp | 5 +- client/simulators/can_debugger.hpp | 4 ++ client/simulators/test.cpp | 6 +- client/simulators/test.hpp | 5 ++ client/ui/better_radiobutton.hpp | 8 +-- client/ui/can_transceive.hpp | 8 +-- client/ui/hex_spinbox.hpp | 8 +-- client/ui/led.hpp | 8 +-- client/ui/plot_wrapper.hpp | 8 +-- client/ui_base.cpp | 15 +++-- client/ui_base.hpp | 23 +------- client/web_socket_wrapper.hpp | 8 +-- external/CMakeLists.txt | 1 - 16 files changed, 113 insertions(+), 186 deletions(-) create mode 100644 client/factory.hpp diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 1a51392..2b40094 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -4,17 +4,26 @@ find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Svg WebSockets) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) file(GLOB_RECURSE ui "ui/*") +file(GLOB_RECURSE sims "simulators/*") set(PROJECT_SOURCES + ${ui} + ${sims} IterableEnum.hpp main.cpp mainwindow.cpp mainwindow.hpp 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 - MANUAL_FINALIZATION ${PROJECT_SOURCES} ) @@ -29,11 +38,12 @@ set_target_properties( target_include_directories(unisim_client PUBLIC ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/ui ${CMAKE_CURRENT_LIST_DIR}/simulators ${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) install(TARGETS unisim_client @@ -41,84 +51,3 @@ install(TARGETS unisim_client LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 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 - $ - $) - -add_custom_target(copy_qwt_to_unisim - COMMAND ${CMAKE_COMMAND} -E copy_if_different - $ - $ - 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 - $ - $) - endforeach() -else() - file(GLOB_RECURSE sims "simulators/*") -endif() diff --git a/client/factory.hpp b/client/factory.hpp new file mode 100644 index 0000000..8817475 --- /dev/null +++ b/client/factory.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include "ui_base.hpp" +#include +#include +#include +#include + +class UIFactory +{ + public: + using Creator = std::function; + + 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 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; \ + } diff --git a/client/mainwindow.cpp b/client/mainwindow.cpp index e7a4a81..3422d37 100644 --- a/client/mainwindow.cpp +++ b/client/mainwindow.cpp @@ -1,4 +1,5 @@ #include "mainwindow.hpp" +#include "factory.hpp" #include "ui_base.hpp" #include "ui_mainwindow.h" #include "web_socket_wrapper.hpp" @@ -9,8 +10,6 @@ #include #include -typedef UI_base *(*Get_UI)(Web_socket_wrapper *, QWidget *); - MainWindow::MainWindow(QUrl ws_url, QString sim, QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), m_error(new QMessageBox()), m_web_socket(new Web_socket_wrapper(ws_url)) @@ -23,33 +22,19 @@ MainWindow::MainWindow(QUrl ws_url, QString sim, QWidget *parent) (spdlog::level::level_enum)level, msg.toStdString()); }); - QDirIterator it(QCoreApplication::applicationDirPath(), QStringList() << "*libui_*.so" << "*libui_*.dll", - QDir::Files, QDirIterator::Subdirectories); - while (it.hasNext()) + for (const QString &name : UIFactory::instance().keys()) { - QLibrary lib; - lib.setFileName(it.next()); - lib.load(); - auto loaded_ui = Get_UI(lib.resolve("get_ui")); - if (loaded_ui == nullptr) + if (auto *w = UIFactory::instance().create(name, m_web_socket.get(), this)) { - SPDLOG_INFO("{} NOT FOUND", lib.fileName().toStdString()); - lib.unload(); - continue; + w->set_name(name); + m_sims.insert(std::make_pair(name, w)); + connect(w, &UI_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}, + (spdlog::level::level_enum)level, msg.toStdString()); + }); } - 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) { - 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()); - }); } // Insert debug sims here @@ -103,7 +88,8 @@ void MainWindow::pase_sim_names(json &sims) { for (json &item : sims) { - ui->comboBox->addItem(QString::fromStdString(item)); + if (m_sims.contains(QString::fromStdString(item))) + ui->comboBox->addItem(QString::fromStdString(item)); } QThread::msleep(30); diff --git a/client/simulators/can_debugger.cpp b/client/simulators/can_debugger.cpp index 33bd794..1e58f0b 100644 --- a/client/simulators/can_debugger.cpp +++ b/client/simulators/can_debugger.cpp @@ -1,10 +1,11 @@ #include "can_debugger.hpp" +#include "factory.hpp" #include "ui_can_debugger.h" -EXPORT_UI(Can_Debugger); +REGISTER_UI(Can_Debugger); 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); diff --git a/client/simulators/can_debugger.hpp b/client/simulators/can_debugger.hpp index 5e18dc2..5a5c185 100644 --- a/client/simulators/can_debugger.hpp +++ b/client/simulators/can_debugger.hpp @@ -13,6 +13,10 @@ class Can_Debugger : public UI_base public: explicit Can_Debugger(Web_socket_wrapper *web_socket = nullptr, QWidget *parent = nullptr); ~Can_Debugger(); + static QString name() + { + return "Can Debugger"; + }; private: Ui::Can_Debugger *ui; diff --git a/client/simulators/test.cpp b/client/simulators/test.cpp index 11f4e34..de8a779 100644 --- a/client/simulators/test.cpp +++ b/client/simulators/test.cpp @@ -1,10 +1,10 @@ #include "test.hpp" +#include "factory.hpp" #include "ui_test.h" -EXPORT_UI(Test_Sim); +REGISTER_UI(Test_Sim); -Test_Sim::Test_Sim(Web_socket_wrapper *web_socket, QWidget *parent) - : UI_base("Test Sim", web_socket, parent), ui(new Ui::Test_Sim) +Test_Sim::Test_Sim(Web_socket_wrapper *web_socket, QWidget *parent) : UI_base(web_socket, parent), ui(new Ui::Test_Sim) { ui->setupUi(this); diff --git a/client/simulators/test.hpp b/client/simulators/test.hpp index 174a862..72f9050 100644 --- a/client/simulators/test.hpp +++ b/client/simulators/test.hpp @@ -14,6 +14,11 @@ class Test_Sim : public UI_base explicit Test_Sim(Web_socket_wrapper *web_socket = nullptr, QWidget *parent = nullptr); ~Test_Sim(); + static QString name() + { + return "Test Sim"; + }; + QLabel *id_to_label(QWidget *widget) override; private: diff --git a/client/ui/better_radiobutton.hpp b/client/ui/better_radiobutton.hpp index a6997bc..ed06d35 100644 --- a/client/ui/better_radiobutton.hpp +++ b/client/ui/better_radiobutton.hpp @@ -2,17 +2,11 @@ #include #include -#ifdef INTERNAL -#define EXPORT Q_DECL_EXPORT -#else -#define EXPORT Q_DECL_IMPORT -#endif - /** * @brief Class representing a better radiobutton group * */ -class EXPORT Better_Radiobutton : public QWidget +class Better_Radiobutton : public QWidget { Q_OBJECT public: diff --git a/client/ui/can_transceive.hpp b/client/ui/can_transceive.hpp index 5eec430..e6e8fc7 100644 --- a/client/ui/can_transceive.hpp +++ b/client/ui/can_transceive.hpp @@ -2,12 +2,6 @@ #include "hex_spinbox.hpp" #include -#ifdef INTERNAL -#define EXPORT Q_DECL_EXPORT -#else -#define EXPORT Q_DECL_IMPORT -#endif - namespace Ui { class Can_Transceive; @@ -17,7 +11,7 @@ class Can_Transceive; * @brief Class representing a CAN transceive UI component * */ -class EXPORT Can_Transceive : public QWidget +class Can_Transceive : public QWidget { Q_OBJECT diff --git a/client/ui/hex_spinbox.hpp b/client/ui/hex_spinbox.hpp index 8ee11ee..2ec7bd3 100644 --- a/client/ui/hex_spinbox.hpp +++ b/client/ui/hex_spinbox.hpp @@ -3,19 +3,13 @@ #include #include -#ifdef INTERNAL -#define EXPORT Q_DECL_EXPORT -#else -#define EXPORT Q_DECL_IMPORT -#endif - /** * @brief Class representing a hexadecimal spin box * @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. * 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 diff --git a/client/ui/led.hpp b/client/ui/led.hpp index 3c74843..5d0977c 100644 --- a/client/ui/led.hpp +++ b/client/ui/led.hpp @@ -1,17 +1,11 @@ #pragma once #include "QPushButton" -#ifdef INTERNAL -#define EXPORT Q_DECL_EXPORT -#else -#define EXPORT Q_DECL_IMPORT -#endif - /** * @brief Class representing an LED widget * */ -class EXPORT Led : public QPushButton +class Led : public QPushButton { Q_OBJECT public: diff --git a/client/ui/plot_wrapper.hpp b/client/ui/plot_wrapper.hpp index 87ebb86..49ee226 100644 --- a/client/ui/plot_wrapper.hpp +++ b/client/ui/plot_wrapper.hpp @@ -4,17 +4,11 @@ #include #include -#ifdef INTERNAL -#define EXPORT Q_DECL_EXPORT -#else -#define EXPORT Q_DECL_IMPORT -#endif - /** * @brief Class wrapping a QwtPlot for plotting data * */ -class EXPORT Plot_wrapper : public QwtPlot +class Plot_wrapper : public QwtPlot { Q_OBJECT public: diff --git a/client/ui_base.cpp b/client/ui_base.cpp index ae34503..17b6935 100644 --- a/client/ui_base.cpp +++ b/client/ui_base.cpp @@ -7,9 +7,8 @@ #include #include -UI_base::UI_base(QString name, Web_socket_wrapper *web_socket, QWidget *parent) - : QMainWindow{parent}, m_timer_update(new QTimer()), m_error(new QMessageBox(this)), m_web_socket(web_socket), - m_name(name) +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) { this->setWindowState(Qt::WindowMaximized); 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) { return m_ui_lookup.at(id); } -QString UI_base::name() const -{ - return m_name; -} - void UI_base::showEvent(QShowEvent *event) { QWidget::showEvent(event); diff --git a/client/ui_base.hpp b/client/ui_base.hpp index 7606ccb..a19016a 100644 --- a/client/ui_base.hpp +++ b/client/ui_base.hpp @@ -5,12 +5,6 @@ #include #include -#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(QTimer); Q_FORWARD_DECLARE_OBJC_CLASS(QLabel); @@ -19,11 +13,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QMessageBox); using json = nlohmann::json; #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_TRACE(msg) LOG_SRC_LOC(Log_level_enum::trace, msg) @@ -36,7 +25,7 @@ using json = nlohmann::json; /** * @brief Base class for client UIs */ -class EXPORT UI_base : public QMainWindow +class UI_base : public QMainWindow { Q_OBJECT public: @@ -58,13 +47,8 @@ class EXPORT UI_base : public QMainWindow * @param api The weboscket connection to the server API * @param parent The parent widget */ - explicit UI_base(QString name, Web_socket_wrapper *api, QWidget *parent = nullptr); - /** - * @brief Get the name of the simulator - * - * @return QString The name of the simulator - */ - QString name() const; + explicit UI_base(Web_socket_wrapper *api, QWidget *parent = nullptr); + void set_name(QString name); /** * @brief Get the UI element by its ID * @@ -216,7 +200,6 @@ class EXPORT UI_base : public QMainWindow private: Web_socket_wrapper *m_web_socket; QString m_name; - QTimer *m_timer_update; uint32_t m_refresh_rate; QMessageBox *m_error; diff --git a/client/web_socket_wrapper.hpp b/client/web_socket_wrapper.hpp index 9a7fe99..21280cb 100644 --- a/client/web_socket_wrapper.hpp +++ b/client/web_socket_wrapper.hpp @@ -2,12 +2,6 @@ #include #include -#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(QTimer); using json = nlohmann::json; @@ -16,7 +10,7 @@ using json = nlohmann::json; * @brief Class wrapping a WebSocket connection * */ -class EXPORT Web_socket_wrapper : public QObject +class Web_socket_wrapper : public QObject { Q_OBJECT public: diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 3a4b2fe..7502cfa 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -1,4 +1,3 @@ -set(QWT_BUILD_SHARED ON) set(COLOR_BUILD_PIC ON) set(SPDLOG_BUILD_PIC ON) add_subdirectory(color)