diff --git a/external/imgui-backend-qt b/external/imgui-backend-qt index 69447758..a914f181 160000 --- a/external/imgui-backend-qt +++ b/external/imgui-backend-qt @@ -1 +1 @@ -Subproject commit 6944775887e61d4d8185568e0205af5b3b483801 +Subproject commit a914f1811185f5959d50f2a199420dee4d15ae74 diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 430af964..246432b6 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -93,12 +93,14 @@ set(SRC_MAP source/scwx/qt/map/alert_layer.cpp source/scwx/qt/map/radar_range_layer.cpp) set(HDR_MODEL source/scwx/qt/model/alert_model.hpp source/scwx/qt/model/alert_proxy_model.hpp + source/scwx/qt/model/imgui_context_model.hpp source/scwx/qt/model/radar_product_model.hpp source/scwx/qt/model/radar_site_model.hpp source/scwx/qt/model/tree_item.hpp source/scwx/qt/model/tree_model.hpp) set(SRC_MODEL source/scwx/qt/model/alert_model.cpp source/scwx/qt/model/alert_proxy_model.cpp + source/scwx/qt/model/imgui_context_model.cpp source/scwx/qt/model/radar_product_model.cpp source/scwx/qt/model/radar_site_model.cpp source/scwx/qt/model/tree_item.cpp @@ -119,6 +121,8 @@ set(SRC_TYPES source/scwx/qt/types/radar_product_record.cpp set(HDR_UI source/scwx/qt/ui/alert_dialog.hpp source/scwx/qt/ui/alert_dock_widget.hpp source/scwx/qt/ui/flow_layout.hpp + source/scwx/qt/ui/imgui_debug_dialog.hpp + source/scwx/qt/ui/imgui_debug_widget.hpp source/scwx/qt/ui/level2_products_widget.hpp source/scwx/qt/ui/level2_settings_widget.hpp source/scwx/qt/ui/level3_products_widget.hpp @@ -126,12 +130,15 @@ set(HDR_UI source/scwx/qt/ui/alert_dialog.hpp set(SRC_UI source/scwx/qt/ui/alert_dialog.cpp source/scwx/qt/ui/alert_dock_widget.cpp source/scwx/qt/ui/flow_layout.cpp + source/scwx/qt/ui/imgui_debug_dialog.cpp + source/scwx/qt/ui/imgui_debug_widget.cpp source/scwx/qt/ui/level2_products_widget.cpp source/scwx/qt/ui/level2_settings_widget.cpp source/scwx/qt/ui/level3_products_widget.cpp source/scwx/qt/ui/radar_site_dialog.cpp) set(UI_UI source/scwx/qt/ui/alert_dialog.ui source/scwx/qt/ui/alert_dock_widget.ui + source/scwx/qt/ui/imgui_debug_dialog.ui source/scwx/qt/ui/radar_site_dialog.ui) set(HDR_UTIL source/scwx/qt/util/font.hpp source/scwx/qt/util/font_buffer.hpp diff --git a/scwx-qt/source/scwx/qt/main/main_window.cpp b/scwx-qt/source/scwx/qt/main/main_window.cpp index 5aff3bbf..3e06b47a 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.cpp +++ b/scwx-qt/source/scwx/qt/main/main_window.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ public: level2SettingsWidget_ {nullptr}, level3ProductsWidget_ {nullptr}, alertDockWidget_ {nullptr}, + imGuiDebugDialog_ {nullptr}, radarSiteDialog_ {nullptr}, radarProductModel_ {nullptr}, textEventManager_ {manager::TextEventManager::Instance()}, @@ -109,8 +111,9 @@ public: ui::Level3ProductsWidget* level3ProductsWidget_; - ui::AlertDockWidget* alertDockWidget_; - ui::RadarSiteDialog* radarSiteDialog_; + ui::AlertDockWidget* alertDockWidget_; + ui::ImGuiDebugDialog* imGuiDebugDialog_; + ui::RadarSiteDialog* radarSiteDialog_; std::unique_ptr radarProductModel_; std::shared_ptr textEventManager_; @@ -196,6 +199,9 @@ MainWindow::MainWindow(QWidget* parent) : ui->settingsFrame->layout()->addWidget(p->level2SettingsWidget_); p->level2SettingsWidget_->setVisible(false); + // ImGui Debug Dialog + p->imGuiDebugDialog_ = new ui::ImGuiDebugDialog(this); + auto mapSettings = manager::SettingsManager::map_settings(); for (size_t i = 0; i < p->maps_.size(); i++) { @@ -323,6 +329,11 @@ void MainWindow::on_actionExit_triggered() close(); } +void MainWindow::on_actionImGuiDebug_triggered() +{ + p->imGuiDebugDialog_->show(); +} + void MainWindow::on_radarSiteSelectButton_clicked() { p->radarSiteDialog_->show(); diff --git a/scwx-qt/source/scwx/qt/main/main_window.hpp b/scwx-qt/source/scwx/qt/main/main_window.hpp index ab708b58..3bcebe8d 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.hpp +++ b/scwx-qt/source/scwx/qt/main/main_window.hpp @@ -35,6 +35,7 @@ private slots: void on_actionOpenNexrad_triggered(); void on_actionOpenTextEvent_triggered(); void on_actionExit_triggered(); + void on_actionImGuiDebug_triggered(); void on_radarSiteSelectButton_clicked(); void on_resourceTreeCollapseAllButton_clicked(); void on_resourceTreeExpandAllButton_clicked(); diff --git a/scwx-qt/source/scwx/qt/main/main_window.ui b/scwx-qt/source/scwx/qt/main/main_window.ui index 61159a56..706dbae7 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.ui +++ b/scwx-qt/source/scwx/qt/main/main_window.ui @@ -35,7 +35,7 @@ 0 0 1024 - 22 + 21 @@ -67,8 +67,15 @@ + + + &Debug + + + + @@ -342,6 +349,11 @@ &Alerts + + + &ImGui Debug + + diff --git a/scwx-qt/source/scwx/qt/manager/resource_manager.cpp b/scwx-qt/source/scwx/qt/manager/resource_manager.cpp index ffbd364f..467832cb 100644 --- a/scwx-qt/source/scwx/qt/manager/resource_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/resource_manager.cpp @@ -4,11 +4,6 @@ #include #include -#include -#include -#include -#include - namespace scwx { namespace qt @@ -17,45 +12,21 @@ namespace manager { namespace ResourceManager { -static const std::string logPrefix_ = "scwx::qt::manager::ResourceManager"; +static const std::string logPrefix_ = "scwx::qt::manager::resource_manager"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); -static void InitializeImGui(); static void LoadFonts(); static void LoadTextures(); -static void ShutdownImGui(); - -static std::unique_ptr surface_ {}; void Initialize() { config::CountyDatabase::Initialize(); - InitializeImGui(); LoadFonts(); LoadTextures(); } -void Shutdown() -{ - ShutdownImGui(); -} - -static void InitializeImGui() -{ - // Create OpenGL Offscreen Surface - surface_ = std::make_unique(); - surface_->create(); - if (!QOpenGLContext::globalShareContext()->makeCurrent(surface_.get())) - { - logger_->warn("Failed to initialize offscreen surface"); - } - - // Initialize ImGui - ImGui::CreateContext(); - ImGui_ImplOpenGL3_Init(); - QOpenGLContext::globalShareContext()->doneCurrent(); -} +void Shutdown() {} static void LoadFonts() { @@ -73,14 +44,6 @@ static void LoadTextures() textureAtlas.BuildAtlas(8, 8); } -static void ShutdownImGui() -{ - QOpenGLContext::globalShareContext()->makeCurrent(surface_.get()); - ImGui_ImplOpenGL3_Shutdown(); - ImGui::DestroyContext(); - QOpenGLContext::globalShareContext()->doneCurrent(); -} - } // namespace ResourceManager } // namespace manager } // namespace qt diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp index 581d6199..4f015e62 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -8,12 +8,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -60,6 +62,7 @@ public: settings_(settings), map_(), layerList_ {}, + imGuiRendererInitialized_ {false}, radarProductManager_ {nullptr}, radarProductLayer_ {nullptr}, alertLayer_ {std::make_shared(context_)}, @@ -79,8 +82,33 @@ public: { SetRadarSite(scwx::qt::manager::SettingsManager::general_settings() ->default_radar_site()); + + // Create ImGui Context + static size_t currentMapId_ {0u}; + imGuiContextName_ = std::format("Map {}", ++currentMapId_); + imGuiContext_ = + model::ImGuiContextModel::Instance().CreateContext(imGuiContextName_); + + // Initialize ImGui Qt backend + ImGui_ImplQt_Init(); + ImGui_ImplQt_RegisterWidget(widget_); + } + + ~MapWidgetImpl() + { + // Set ImGui Context + ImGui::SetCurrentContext(imGuiContext_); + + // Shutdown ImGui Context + if (imGuiRendererInitialized_) + { + ImGui_ImplOpenGL3_Shutdown(); + } + ImGui_ImplQt_Shutdown(); + + // Destroy ImGui Context + model::ImGuiContextModel::Instance().DestroyContext(imGuiContextName_); } - ~MapWidgetImpl() = default; void AddLayer(const std::string& id, std::shared_ptr layer, @@ -103,6 +131,10 @@ public: std::shared_ptr map_; std::list layerList_; + ImGuiContext* imGuiContext_; + std::string imGuiContextName_; + bool imGuiRendererInitialized_; + std::shared_ptr radarProductManager_; std::shared_ptr colorTable_; @@ -136,6 +168,8 @@ MapWidget::MapWidget(const QMapLibreGL::Settings& settings) : p(std::make_unique(this, settings)) { setFocusPolicy(Qt::StrongFocus); + + ImGui_ImplQt_RegisterWidget(this); } MapWidget::~MapWidget() @@ -644,6 +678,11 @@ void MapWidget::initializeGL() makeCurrent(); p->context_->gl().initializeOpenGLFunctions(); + // Initialize ImGui OpenGL3 backend + ImGui::SetCurrentContext(p->imGuiContext_); + ImGui_ImplOpenGL3_Init(); + p->imGuiRendererInitialized_ = true; + p->map_.reset( new QMapLibreGL::Map(nullptr, p->settings_, size(), pixelRatio())); p->context_->set_map(p->map_); @@ -686,10 +725,10 @@ void MapWidget::paintGL() p->frameDraws_++; // Setup ImGui Frame - ImGui::GetIO().DisplaySize = {static_cast(size().width()), - static_cast(size().height())}; + ImGui::SetCurrentContext(p->imGuiContext_); // Start ImGui Frame + ImGui_ImplQt_NewFrame(this); ImGui_ImplOpenGL3_NewFrame(); ImGui::NewFrame(); diff --git a/scwx-qt/source/scwx/qt/model/imgui_context_model.cpp b/scwx-qt/source/scwx/qt/model/imgui_context_model.cpp new file mode 100644 index 00000000..13b09198 --- /dev/null +++ b/scwx-qt/source/scwx/qt/model/imgui_context_model.cpp @@ -0,0 +1,143 @@ +#include +#include +#include + +#include + +namespace scwx +{ +namespace qt +{ +namespace model +{ + +static const std::string logPrefix_ = "scwx::qt::model::imgui_context_model"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); + +class ImGuiContextModelImpl +{ +public: + explicit ImGuiContextModelImpl() {} + + ~ImGuiContextModelImpl() = default; + + std::vector contexts_ {}; +}; + +ImGuiContextModel::ImGuiContextModel() : + QAbstractListModel(nullptr), p {std::make_unique()} +{ +} + +ImGuiContextModel::~ImGuiContextModel() {} + +int ImGuiContextModel::rowCount(const QModelIndex& parent) const +{ + return parent.isValid() ? 0 : static_cast(p->contexts_.size()); +} + +QVariant ImGuiContextModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) + { + return {}; + } + + const int row = index.row(); + if (row >= p->contexts_.size() || row < 0) + { + return {}; + } + + switch (role) + { + case Qt::ItemDataRole::DisplayRole: + return QString("%1: %2") + .arg(p->contexts_[row].id_) + .arg(p->contexts_[row].name_.c_str()); + + case qt::types::ItemDataRole::RawDataRole: + QVariant variant {}; + variant.setValue(p->contexts_[row]); + return variant; + } + + return {}; +} + +QModelIndex ImGuiContextModel::IndexOf(const std::string& contextName) const +{ + // Find context from registry + auto it = + std::find_if(p->contexts_.begin(), + p->contexts_.end(), + [&](auto& info) { return info.name_ == contextName; }); + + if (it != p->contexts_.end()) + { + const int row = it - p->contexts_.begin(); + return createIndex(row, 0, nullptr); + } + + return {}; +} + +ImGuiContext* ImGuiContextModel::CreateContext(const std::string& name) +{ + static size_t nextId_ {0}; + + ImGuiContext* context = ImGui::CreateContext(); + ImGui::SetCurrentContext(context); + + // ImGui Configuration + auto& io = ImGui::GetIO(); + + // Disable automatic configuration loading/saving + io.IniFilename = nullptr; + + // Style + auto& style = ImGui::GetStyle(); + style.WindowMinSize = {10.0f, 10.0f}; + + // Register context + const int nextPosition = static_cast(p->contexts_.size()); + beginInsertRows(QModelIndex(), nextPosition, nextPosition); + p->contexts_.emplace_back(ImGuiContextInfo {nextId_++, name, context}); + endInsertRows(); + + return context; +} + +void ImGuiContextModel::DestroyContext(const std::string& name) +{ + // Find context from registry + auto it = std::find_if(p->contexts_.begin(), + p->contexts_.end(), + [&](auto& info) { return info.name_ == name; }); + + if (it != p->contexts_.end()) + { + const int position = it - p->contexts_.begin(); + + // Destroy context + ImGui::SetCurrentContext(it->context_); + ImGui::DestroyContext(); + + // Erase context from index + beginRemoveRows(QModelIndex(), position, position); + p->contexts_.erase(it); + endRemoveRows(); + } +} + +ImGuiContextModel& ImGuiContextModel::Instance() +{ + static ImGuiContextModel instance_ {}; + return instance_; +} + +bool ImGuiContextInfo::operator==(const ImGuiContextInfo& o) const = default; + +} // namespace model +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/model/imgui_context_model.hpp b/scwx-qt/source/scwx/qt/model/imgui_context_model.hpp new file mode 100644 index 00000000..7241a197 --- /dev/null +++ b/scwx-qt/source/scwx/qt/model/imgui_context_model.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include +#include + +#include + +struct ImGuiContext; + +namespace scwx +{ +namespace qt +{ +namespace model +{ + +class ImGuiContextModelImpl; + +struct ImGuiContextInfo +{ + size_t id_ {}; + std::string name_ {}; + ImGuiContext* context_ {}; + + bool operator==(const ImGuiContextInfo& o) const; +}; + +class ImGuiContextModel : public QAbstractListModel +{ +private: + Q_OBJECT + Q_DISABLE_COPY(ImGuiContextModel) + +public: + explicit ImGuiContextModel(); + ~ImGuiContextModel(); + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + + QVariant data(const QModelIndex& index, + int role = Qt::DisplayRole) const override; + + QModelIndex IndexOf(const std::string& contextName) const; + + ImGuiContext* CreateContext(const std::string& name); + void DestroyContext(const std::string& name); + + static ImGuiContextModel& Instance(); + +signals: + void ContextsUpdated(); + +private: + friend class ImGuiContextModelImpl; + std::unique_ptr p; +}; + +} // namespace model +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/types/qt_types.hpp b/scwx-qt/source/scwx/qt/types/qt_types.hpp index d034409c..657b846f 100644 --- a/scwx-qt/source/scwx/qt/types/qt_types.hpp +++ b/scwx-qt/source/scwx/qt/types/qt_types.hpp @@ -12,7 +12,8 @@ namespace types enum ItemDataRole { SortRole = Qt::UserRole, - TimePointRole + TimePointRole, + RawDataRole }; } // namespace types diff --git a/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.cpp b/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.cpp new file mode 100644 index 00000000..a416e1cd --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.cpp @@ -0,0 +1,69 @@ +#include "imgui_debug_dialog.hpp" +#include "ui_imgui_debug_dialog.h" + +#include +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace ui +{ + +static const std::string logPrefix_ = "scwx::qt::ui::imgui_debug_dialog"; + +class ImGuiDebugDialogImpl +{ +public: + explicit ImGuiDebugDialogImpl() : imGuiDebugWidget_ {nullptr} {} + ~ImGuiDebugDialogImpl() = default; + + ImGuiDebugWidget* imGuiDebugWidget_; +}; + +ImGuiDebugDialog::ImGuiDebugDialog(QWidget* parent) : + QDialog(parent), + p {std::make_unique()}, + ui(new Ui::ImGuiDebugDialog) +{ + ui->setupUi(this); + + // ImGui Debug Widget + p->imGuiDebugWidget_ = new ImGuiDebugWidget(this); + p->imGuiDebugWidget_->setSizePolicy(QSizePolicy::Policy::Expanding, + QSizePolicy::Policy::Expanding); + ui->verticalLayout->insertWidget(0, p->imGuiDebugWidget_); + + // Context Combo Box + auto& contextModel = model::ImGuiContextModel::Instance(); + auto index = contextModel.IndexOf(p->imGuiDebugWidget_->context_name()); + ui->contextComboBox->setModel(&contextModel); + ui->contextComboBox->setCurrentIndex(index.row()); + + connect( + ui->contextComboBox, + &QComboBox::currentIndexChanged, + [=](int row) + { + auto& contextModel = model::ImGuiContextModel::Instance(); + auto index = contextModel.index(row, 0); + if (index.isValid()) + { + QVariant data = contextModel.data(index, qt::types::RawDataRole); + auto contextInfo = data.value(); + + p->imGuiDebugWidget_->set_current_context(contextInfo.context_); + } + }); +} + +ImGuiDebugDialog::~ImGuiDebugDialog() +{ + delete ui; +} + +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.hpp b/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.hpp new file mode 100644 index 00000000..f08be4ff --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include + +namespace Ui +{ +class ImGuiDebugDialog; +} + +namespace scwx +{ +namespace qt +{ +namespace ui +{ + +class ImGuiDebugDialogImpl; + +class ImGuiDebugDialog : public QDialog +{ +private: + Q_DISABLE_COPY(ImGuiDebugDialog) + +public: + explicit ImGuiDebugDialog(QWidget* parent = nullptr); + ~ImGuiDebugDialog(); + +private: + friend class ImGuiDebugDialogImpl; + std::unique_ptr p; + Ui::ImGuiDebugDialog* ui; +}; + +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.ui b/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.ui new file mode 100644 index 00000000..5752a7c1 --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.ui @@ -0,0 +1,104 @@ + + + ImGuiDebugDialog + + + + 0 + 0 + 592 + 754 + + + + ImGui Debug + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Context + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + + + + buttonBox + accepted() + ImGuiDebugDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ImGuiDebugDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp new file mode 100644 index 00000000..066ba59d --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp @@ -0,0 +1,137 @@ +#include +#include + +#include + +#include +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace ui +{ + +static const std::string logPrefix_ = "scwx::qt::ui::imgui_debug_widget"; + +class ImGuiDebugWidgetImpl +{ +public: + explicit ImGuiDebugWidgetImpl(ImGuiDebugWidget* self) : self_ {self} + { + // Create ImGui Context + static size_t currentIndex_ {0u}; + contextName_ = std::format("ImGui Debug {}", ++currentIndex_); + context_ = + model::ImGuiContextModel::Instance().CreateContext(contextName_); + currentContext_ = context_; + + // Initialize ImGui Qt backend + ImGui_ImplQt_Init(); + ImGui_ImplQt_RegisterWidget(self_); + } + + ~ImGuiDebugWidgetImpl() + { + // Set ImGui Context + ImGui::SetCurrentContext(context_); + + // Shutdown ImGui Context + if (imGuiRendererInitialized_) + { + ImGui_ImplOpenGL3_Shutdown(); + } + ImGui_ImplQt_Shutdown(); + + // Destroy ImGui Context + model::ImGuiContextModel::Instance().DestroyContext(contextName_); + } + + ImGuiDebugWidget* self_; + ImGuiContext* context_; + std::string contextName_; + + ImGuiContext* currentContext_; + + std::set renderedSet_ {}; + bool imGuiRendererInitialized_ {false}; +}; + +ImGuiDebugWidget::ImGuiDebugWidget(QWidget* parent) : + QOpenGLWidget(parent), p {std::make_unique(this)} +{ + // Accept focus for keyboard events + setFocusPolicy(Qt::StrongFocus); +} + +ImGuiDebugWidget::~ImGuiDebugWidget() {} + +std::string ImGuiDebugWidget::context_name() const +{ + return p->contextName_; +} + +void ImGuiDebugWidget::set_current_context(ImGuiContext* context) +{ + if (context == p->currentContext_) + { + return; + } + + // Unregister widget with current context + ImGui::SetCurrentContext(p->currentContext_); + ImGui_ImplQt_UnregisterWidget(this); + + p->currentContext_ = context; + + // Register widget with new context + ImGui::SetCurrentContext(context); + ImGui_ImplQt_RegisterWidget(this); + + // Queue an update + update(); +} + +void ImGuiDebugWidget::initializeGL() +{ + makeCurrent(); + + // Initialize ImGui OpenGL3 backend + ImGui::SetCurrentContext(p->context_); + ImGui_ImplOpenGL3_Init(); + p->imGuiRendererInitialized_ = true; +} + +void ImGuiDebugWidget::paintGL() +{ + ImGui::SetCurrentContext(p->currentContext_); + + ImGui_ImplQt_NewFrame(this); + ImGui_ImplOpenGL3_NewFrame(); + + ImGui::NewFrame(); + + if (!p->renderedSet_.contains(p->currentContext_)) + { + // Set initial position of demo window + ImGui::SetNextWindowPos(ImVec2 {width() / 2.0f, height() / 2.0f}, + ImGuiCond_FirstUseEver, + ImVec2 {0.5f, 0.5f}); + ImGui::Begin("Dear ImGui Demo"); + ImGui::End(); + + p->renderedSet_.insert(p->currentContext_); + update(); + } + + ImGui::ShowDemoWindow(); + + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); +} + +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.hpp b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.hpp new file mode 100644 index 00000000..695a6be9 --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include + +struct ImGuiContext; + +namespace Ui +{ +class ImGuiDebugWidget; +} + +namespace scwx +{ +namespace qt +{ +namespace ui +{ + +class ImGuiDebugWidgetImpl; + +class ImGuiDebugWidget : public QOpenGLWidget +{ +private: + Q_DISABLE_COPY(ImGuiDebugWidget) + +public: + explicit ImGuiDebugWidget(QWidget* parent = nullptr); + ~ImGuiDebugWidget(); + + std::string context_name() const; + + void set_current_context(ImGuiContext* context); + + void initializeGL() override; + void paintGL() override; + +private: + friend class ImGuiDebugWidgetImpl; + std::unique_ptr p; +}; + +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/test/source/scwx/qt/manager/imgui_manager.test.cpp b/test/source/scwx/qt/manager/imgui_manager.test.cpp new file mode 100644 index 00000000..e25cee22 --- /dev/null +++ b/test/source/scwx/qt/manager/imgui_manager.test.cpp @@ -0,0 +1,44 @@ +#include + +#include + +namespace scwx +{ +namespace qt +{ +namespace manager +{ + +TEST(ImGuiManagerTest, State) +{ + auto& ImGuiManager = ImGuiManager::Instance(); + + ImGuiManager.CreateContext("Context One"); + ImGuiManager.CreateContext("Context Two"); + ImGuiManager.CreateContext("Context Three"); + + auto contexts = ImGuiManager.contexts(); + + ASSERT_EQ(contexts.size(), 3u); + EXPECT_EQ(contexts.at(0).id_, 0u); + EXPECT_EQ(contexts.at(1).id_, 1u); + EXPECT_EQ(contexts.at(2).id_, 2u); + EXPECT_EQ(contexts.at(0).name_, "Context One"); + EXPECT_EQ(contexts.at(1).name_, "Context Two"); + EXPECT_EQ(contexts.at(2).name_, "Context Three"); + EXPECT_NE(contexts.at(0).context_, nullptr); + EXPECT_NE(contexts.at(1).context_, nullptr); + EXPECT_NE(contexts.at(2).context_, nullptr); + + ImGuiManager.DestroyContext("Context Two"); + + auto contexts2 = ImGuiManager.contexts(); + + ASSERT_EQ(contexts2.size(), 2u); + EXPECT_EQ(contexts2.at(0), contexts.at(0)); + EXPECT_EQ(contexts2.at(1), contexts.at(2)); +} + +} // namespace manager +} // namespace qt +} // namespace scwx diff --git a/test/test.cmake b/test/test.cmake index 76984a3a..812a70da 100644 --- a/test/test.cmake +++ b/test/test.cmake @@ -21,7 +21,8 @@ set(SRC_PROVIDER_TESTS source/scwx/provider/aws_level2_data_provider.test.cpp source/scwx/provider/warnings_provider.test.cpp) set(SRC_QT_CONFIG_TESTS source/scwx/qt/config/county_database.test.cpp source/scwx/qt/config/radar_site.test.cpp) -set(SRC_QT_MANAGER_TESTS source/scwx/qt/manager/settings_manager.test.cpp) +set(SRC_QT_MANAGER_TESTS source/scwx/qt/manager/imgui_manager.test.cpp + source/scwx/qt/manager/settings_manager.test.cpp) set(SRC_UTIL_TESTS source/scwx/util/float.test.cpp source/scwx/util/rangebuf.test.cpp source/scwx/util/streams.test.cpp