From cd01bb70b673c1ae53c627643d8e89eb5d0f2dc6 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 26 Nov 2022 00:27:35 -0600 Subject: [PATCH 1/8] Add imgui debug window, still need to use unique contexts --- scwx-qt/scwx-qt.cmake | 5 + scwx-qt/source/scwx/qt/main/main_window.cpp | 15 ++- scwx-qt/source/scwx/qt/main/main_window.hpp | 1 + scwx-qt/source/scwx/qt/main/main_window.ui | 14 ++- .../scwx/qt/manager/resource_manager.cpp | 14 +++ .../source/scwx/qt/ui/imgui_debug_dialog.cpp | 45 ++++++++ .../source/scwx/qt/ui/imgui_debug_dialog.hpp | 36 ++++++ .../source/scwx/qt/ui/imgui_debug_dialog.ui | 104 ++++++++++++++++++ .../source/scwx/qt/ui/imgui_debug_widget.cpp | 56 ++++++++++ .../source/scwx/qt/ui/imgui_debug_widget.hpp | 38 +++++++ 10 files changed, 325 insertions(+), 3 deletions(-) create mode 100644 scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.cpp create mode 100644 scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.hpp create mode 100644 scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.ui create mode 100644 scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp create mode 100644 scwx-qt/source/scwx/qt/ui/imgui_debug_widget.hpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 430af964..82d25f0a 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -119,6 +119,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 +128,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..ad299533 100644 --- a/scwx-qt/source/scwx/qt/manager/resource_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/resource_manager.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -53,8 +54,20 @@ static void InitializeImGui() // Initialize ImGui ImGui::CreateContext(); + ImGui_ImplQt_Init(); ImGui_ImplOpenGL3_Init(); QOpenGLContext::globalShareContext()->doneCurrent(); + + // 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}; } static void LoadFonts() @@ -77,6 +90,7 @@ static void ShutdownImGui() { QOpenGLContext::globalShareContext()->makeCurrent(surface_.get()); ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplQt_Shutdown(); ImGui::DestroyContext(); QOpenGLContext::globalShareContext()->doneCurrent(); } 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..75e90682 --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.cpp @@ -0,0 +1,45 @@ +#include "imgui_debug_dialog.hpp" +#include "ui_imgui_debug_dialog.h" + +#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_); +} + +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..a2790a62 --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.ui @@ -0,0 +1,104 @@ + + + ImGuiDebugDialog + + + + 0 + 0 + 570 + 760 + + + + 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..63998602 --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp @@ -0,0 +1,56 @@ +#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} + { + // ImGui Configuration + auto& io = ImGui::GetIO(); + + // Initialize Qt backend + ImGui_ImplQt_RegisterWidget(self_); + } + ~ImGuiDebugWidgetImpl() {} + + ImGuiDebugWidget* self_; +}; + +ImGuiDebugWidget::ImGuiDebugWidget(QWidget* parent) : + QOpenGLWidget(parent), p {std::make_unique(this)} +{ +} + +void ImGuiDebugWidget::initializeGL() {} + +void ImGuiDebugWidget::paintGL() +{ + ImGui_ImplQt_NewFrame(this); + ImGui_ImplOpenGL3_NewFrame(); + + ImGui::NewFrame(); + + ImGui::ShowDemoWindow(); + + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); +} + +ImGuiDebugWidget::~ImGuiDebugWidget() {} + +} // 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..0294b1bd --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include + +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(); + + void initializeGL() override; + void paintGL() override; + +private: + friend class ImGuiDebugWidgetImpl; + std::unique_ptr p; +}; + +} // namespace ui +} // namespace qt +} // namespace scwx From 2347eff04d5f688dc2dad4e4af4346e0bcde0046 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 26 Nov 2022 09:29:28 -0600 Subject: [PATCH 2/8] Qt backend support for multiple contexts --- external/imgui-backend-qt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/imgui-backend-qt b/external/imgui-backend-qt index 69447758..0ebc0fe7 160000 --- a/external/imgui-backend-qt +++ b/external/imgui-backend-qt @@ -1 +1 @@ -Subproject commit 6944775887e61d4d8185568e0205af5b3b483801 +Subproject commit 0ebc0fe7fa88aa3d1eb58b2f040f11ba45227829 From fef3c597d0870219b72e8d0afb5a400d087005bd Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 26 Nov 2022 21:46:57 -0600 Subject: [PATCH 3/8] ImGui unique contexts --- .../scwx/qt/manager/resource_manager.cpp | 4 +- scwx-qt/source/scwx/qt/map/map_widget.cpp | 39 ++++++++++++-- .../source/scwx/qt/ui/imgui_debug_dialog.ui | 4 +- .../source/scwx/qt/ui/imgui_debug_widget.cpp | 52 +++++++++++++++++-- 4 files changed, 89 insertions(+), 10 deletions(-) diff --git a/scwx-qt/source/scwx/qt/manager/resource_manager.cpp b/scwx-qt/source/scwx/qt/manager/resource_manager.cpp index ad299533..c5eff320 100644 --- a/scwx-qt/source/scwx/qt/manager/resource_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/resource_manager.cpp @@ -27,6 +27,7 @@ static void LoadTextures(); static void ShutdownImGui(); static std::unique_ptr surface_ {}; +static ImGuiContext* imGuiContext_ {}; void Initialize() { @@ -53,7 +54,7 @@ static void InitializeImGui() } // Initialize ImGui - ImGui::CreateContext(); + imGuiContext_ = ImGui::CreateContext(); ImGui_ImplQt_Init(); ImGui_ImplOpenGL3_Init(); QOpenGLContext::globalShareContext()->doneCurrent(); @@ -89,6 +90,7 @@ static void LoadTextures() static void ShutdownImGui() { QOpenGLContext::globalShareContext()->makeCurrent(surface_.get()); + ImGui::SetCurrentContext(imGuiContext_); ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplQt_Shutdown(); ImGui::DestroyContext(); diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp index 581d6199..30eca271 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -60,6 +61,7 @@ public: settings_(settings), map_(), layerList_ {}, + imGuiContext_ {ImGui::CreateContext()}, radarProductManager_ {nullptr}, radarProductLayer_ {nullptr}, alertLayer_ {std::make_shared(context_)}, @@ -79,8 +81,31 @@ public: { SetRadarSite(scwx::qt::manager::SettingsManager::general_settings() ->default_radar_site()); + + // Set ImGui Context + ImGui::SetCurrentContext(imGuiContext_); + + // ImGui Configuration + auto& io = ImGui::GetIO(); + + // Disable automatic configuration loading/saving + io.IniFilename = nullptr; + + // Initialize ImGui Qt backend + ImGui_ImplQt_Init(); + ImGui_ImplQt_RegisterWidget(widget_); + } + + ~MapWidgetImpl() + { + // Set ImGui Context + ImGui::SetCurrentContext(imGuiContext_); + + // Shutdown ImGui Context + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplQt_Shutdown(); + ImGui::DestroyContext(imGuiContext_); } - ~MapWidgetImpl() = default; void AddLayer(const std::string& id, std::shared_ptr layer, @@ -103,6 +128,8 @@ public: std::shared_ptr map_; std::list layerList_; + ImGuiContext* imGuiContext_; + std::shared_ptr radarProductManager_; std::shared_ptr colorTable_; @@ -136,6 +163,8 @@ MapWidget::MapWidget(const QMapLibreGL::Settings& settings) : p(std::make_unique(this, settings)) { setFocusPolicy(Qt::StrongFocus); + + ImGui_ImplQt_RegisterWidget(this); } MapWidget::~MapWidget() @@ -644,6 +673,10 @@ void MapWidget::initializeGL() makeCurrent(); p->context_->gl().initializeOpenGLFunctions(); + // Initialize ImGui OpenGL3 backend + ImGui::SetCurrentContext(p->imGuiContext_); + ImGui_ImplOpenGL3_Init(); + p->map_.reset( new QMapLibreGL::Map(nullptr, p->settings_, size(), pixelRatio())); p->context_->set_map(p->map_); @@ -686,10 +719,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/ui/imgui_debug_dialog.ui b/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.ui index a2790a62..5752a7c1 100644 --- a/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.ui +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.ui @@ -6,8 +6,8 @@ 0 0 - 570 - 760 + 592 + 754 diff --git a/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp index 63998602..0764cf62 100644 --- a/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp @@ -16,33 +16,77 @@ static const std::string logPrefix_ = "scwx::qt::ui::imgui_debug_widget"; class ImGuiDebugWidgetImpl { public: - explicit ImGuiDebugWidgetImpl(ImGuiDebugWidget* self) : self_ {self} + explicit ImGuiDebugWidgetImpl(ImGuiDebugWidget* self) : + self_ {self}, context_ {ImGui::CreateContext()} { + // Set ImGui Context + ImGui::SetCurrentContext(context_); + // ImGui Configuration auto& io = ImGui::GetIO(); - // Initialize Qt backend + // Disable automatic configuration loading/saving + io.IniFilename = nullptr; + + // Initialize ImGui Qt backend + ImGui_ImplQt_Init(); ImGui_ImplQt_RegisterWidget(self_); } - ~ImGuiDebugWidgetImpl() {} + + ~ImGuiDebugWidgetImpl() + { + // Set ImGui Context + ImGui::SetCurrentContext(context_); + + // Shutdown ImGui Context + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplQt_Shutdown(); + ImGui::DestroyContext(context_); + } ImGuiDebugWidget* self_; + ImGuiContext* context_; + + bool firstRender_ {true}; }; ImGuiDebugWidget::ImGuiDebugWidget(QWidget* parent) : QOpenGLWidget(parent), p {std::make_unique(this)} { + // Accept focus for keyboard events + setFocusPolicy(Qt::StrongFocus); } -void ImGuiDebugWidget::initializeGL() {} +void ImGuiDebugWidget::initializeGL() +{ + makeCurrent(); + + // Initialize ImGui OpenGL3 backend + ImGui::SetCurrentContext(p->context_); + ImGui_ImplOpenGL3_Init(); +} void ImGuiDebugWidget::paintGL() { + ImGui::SetCurrentContext(p->context_); + ImGui_ImplQt_NewFrame(this); ImGui_ImplOpenGL3_NewFrame(); ImGui::NewFrame(); + if (p->firstRender_) + { + // 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->firstRender_ = false; + } + ImGui::ShowDemoWindow(); ImGui::Render(); From ee2ec329da3c642c89dd67a86eda8cade84f1906 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 27 Nov 2022 10:27:30 -0600 Subject: [PATCH 4/8] Add ImGui Manager to manage creation and deletion of contexts --- scwx-qt/scwx-qt.cmake | 6 +- .../source/scwx/qt/manager/imgui_manager.cpp | 92 +++++++++++++++++++ .../source/scwx/qt/manager/imgui_manager.hpp | 55 +++++++++++ .../scwx/qt/manager/imgui_manager.test.cpp | 44 +++++++++ test/test.cmake | 3 +- 5 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 scwx-qt/source/scwx/qt/manager/imgui_manager.cpp create mode 100644 scwx-qt/source/scwx/qt/manager/imgui_manager.hpp create mode 100644 test/source/scwx/qt/manager/imgui_manager.test.cpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 82d25f0a..688a2e7b 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -60,12 +60,14 @@ set(HDR_GL_DRAW source/scwx/qt/gl/draw/draw_item.hpp set(SRC_GL_DRAW source/scwx/qt/gl/draw/draw_item.cpp source/scwx/qt/gl/draw/geo_line.cpp source/scwx/qt/gl/draw/rectangle.cpp) -set(HDR_MANAGER source/scwx/qt/manager/radar_product_manager.hpp +set(HDR_MANAGER source/scwx/qt/manager/imgui_manager.hpp + source/scwx/qt/manager/radar_product_manager.hpp source/scwx/qt/manager/radar_product_manager_notifier.hpp source/scwx/qt/manager/resource_manager.hpp source/scwx/qt/manager/settings_manager.hpp source/scwx/qt/manager/text_event_manager.hpp) -set(SRC_MANAGER source/scwx/qt/manager/radar_product_manager.cpp +set(SRC_MANAGER source/scwx/qt/manager/imgui_manager.cpp + source/scwx/qt/manager/radar_product_manager.cpp source/scwx/qt/manager/radar_product_manager_notifier.cpp source/scwx/qt/manager/resource_manager.cpp source/scwx/qt/manager/settings_manager.cpp diff --git a/scwx-qt/source/scwx/qt/manager/imgui_manager.cpp b/scwx-qt/source/scwx/qt/manager/imgui_manager.cpp new file mode 100644 index 00000000..254ec47a --- /dev/null +++ b/scwx-qt/source/scwx/qt/manager/imgui_manager.cpp @@ -0,0 +1,92 @@ +#include +#include + +#include + +namespace scwx +{ +namespace qt +{ +namespace manager +{ + +static const std::string logPrefix_ = "scwx::qt::manager::imgui_manager"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); + +class ImGuiManagerImpl +{ +public: + explicit ImGuiManagerImpl() {} + + ~ImGuiManagerImpl() = default; + + std::vector contexts_ {}; +}; + +ImGuiManager::ImGuiManager() : + QObject(nullptr), p {std::make_unique()} +{ +} + +ImGuiManager::~ImGuiManager() {} + +ImGuiContext* ImGuiManager::CreateContext(const std::string& name) +{ + 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 + static size_t nextId_ {0}; + p->contexts_.emplace_back(ImGuiContextInfo {nextId_++, name, context}); + + // Inform observers contexts have been updated + emit ContextsUpdated(); + + return context; +} + +void ImGuiManager::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()) + { + // Destroy context and erase from index + ImGui::SetCurrentContext(it->context_); + ImGui::DestroyContext(); + p->contexts_.erase(it); + + // Inform observers contexts have been updated + emit ContextsUpdated(); + } +} + +std::vector ImGuiManager::contexts() const +{ + return p->contexts_; +} + +ImGuiManager& ImGuiManager::Instance() +{ + static ImGuiManager instance_; + return instance_; +} + +bool ImGuiContextInfo::operator==(const ImGuiContextInfo& o) const = default; + +} // namespace manager +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/manager/imgui_manager.hpp b/scwx-qt/source/scwx/qt/manager/imgui_manager.hpp new file mode 100644 index 00000000..975a9231 --- /dev/null +++ b/scwx-qt/source/scwx/qt/manager/imgui_manager.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include +#include + +#include + +struct ImGuiContext; + +namespace scwx +{ +namespace qt +{ +namespace manager +{ + +class ImGuiManagerImpl; + +struct ImGuiContextInfo +{ + size_t id_ {}; + std::string name_ {}; + ImGuiContext* context_ {}; + + bool operator==(const ImGuiContextInfo& o) const; +}; + +class ImGuiManager : public QObject +{ +private: + Q_OBJECT + Q_DISABLE_COPY(ImGuiManager) + +public: + explicit ImGuiManager(); + ~ImGuiManager(); + + ImGuiContext* CreateContext(const std::string& name); + void DestroyContext(const std::string& name); + + std::vector contexts() const; + + static ImGuiManager& Instance(); + +signals: + void ContextsUpdated(); + +private: + friend class ImGuiManagerImpl; + std::unique_ptr p; +}; + +} // namespace manager +} // 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 From 0f8b8d73f9f2789053c3e062d128f20f0a00d830 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 27 Nov 2022 11:01:35 -0600 Subject: [PATCH 5/8] Use ImGui Manager to create contexts --- .../scwx/qt/manager/resource_manager.cpp | 57 +------------------ scwx-qt/source/scwx/qt/map/map_widget.cpp | 28 +++++---- .../source/scwx/qt/ui/imgui_debug_widget.cpp | 32 ++++++----- 3 files changed, 37 insertions(+), 80 deletions(-) diff --git a/scwx-qt/source/scwx/qt/manager/resource_manager.cpp b/scwx-qt/source/scwx/qt/manager/resource_manager.cpp index c5eff320..467832cb 100644 --- a/scwx-qt/source/scwx/qt/manager/resource_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/resource_manager.cpp @@ -4,12 +4,6 @@ #include #include -#include -#include -#include -#include -#include - namespace scwx { namespace qt @@ -18,58 +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_ {}; -static ImGuiContext* imGuiContext_ {}; 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 - imGuiContext_ = ImGui::CreateContext(); - ImGui_ImplQt_Init(); - ImGui_ImplOpenGL3_Init(); - QOpenGLContext::globalShareContext()->doneCurrent(); - - // 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}; -} +void Shutdown() {} static void LoadFonts() { @@ -87,16 +44,6 @@ static void LoadTextures() textureAtlas.BuildAtlas(8, 8); } -static void ShutdownImGui() -{ - QOpenGLContext::globalShareContext()->makeCurrent(surface_.get()); - ImGui::SetCurrentContext(imGuiContext_); - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplQt_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 30eca271..be371c2d 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -61,7 +62,7 @@ public: settings_(settings), map_(), layerList_ {}, - imGuiContext_ {ImGui::CreateContext()}, + imGuiRendererInitialized_ {false}, radarProductManager_ {nullptr}, radarProductLayer_ {nullptr}, alertLayer_ {std::make_shared(context_)}, @@ -82,14 +83,11 @@ public: SetRadarSite(scwx::qt::manager::SettingsManager::general_settings() ->default_radar_site()); - // Set ImGui Context - ImGui::SetCurrentContext(imGuiContext_); - - // ImGui Configuration - auto& io = ImGui::GetIO(); - - // Disable automatic configuration loading/saving - io.IniFilename = nullptr; + // Create ImGui Context + static size_t currentMapId_ {0u}; + imGuiContextName_ = std::format("Map {}", ++currentMapId_); + imGuiContext_ = + manager::ImGuiManager::Instance().CreateContext(imGuiContextName_); // Initialize ImGui Qt backend ImGui_ImplQt_Init(); @@ -102,9 +100,14 @@ public: ImGui::SetCurrentContext(imGuiContext_); // Shutdown ImGui Context - ImGui_ImplOpenGL3_Shutdown(); + if (imGuiRendererInitialized_) + { + ImGui_ImplOpenGL3_Shutdown(); + } ImGui_ImplQt_Shutdown(); - ImGui::DestroyContext(imGuiContext_); + + // Destroy ImGui Context + manager::ImGuiManager::Instance().DestroyContext(imGuiContextName_); } void AddLayer(const std::string& id, @@ -129,6 +132,8 @@ public: std::list layerList_; ImGuiContext* imGuiContext_; + std::string imGuiContextName_; + bool imGuiRendererInitialized_; std::shared_ptr radarProductManager_; @@ -676,6 +681,7 @@ void MapWidget::initializeGL() // 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())); diff --git a/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp index 0764cf62..dc4505f6 100644 --- a/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -16,17 +17,12 @@ static const std::string logPrefix_ = "scwx::qt::ui::imgui_debug_widget"; class ImGuiDebugWidgetImpl { public: - explicit ImGuiDebugWidgetImpl(ImGuiDebugWidget* self) : - self_ {self}, context_ {ImGui::CreateContext()} + explicit ImGuiDebugWidgetImpl(ImGuiDebugWidget* self) : self_ {self} { - // Set ImGui Context - ImGui::SetCurrentContext(context_); - - // ImGui Configuration - auto& io = ImGui::GetIO(); - - // Disable automatic configuration loading/saving - io.IniFilename = nullptr; + // Create ImGui Context + static size_t currentIndex_ {0u}; + contextName_ = std::format("ImGui Debug {}", ++currentIndex_); + context_ = manager::ImGuiManager::Instance().CreateContext(contextName_); // Initialize ImGui Qt backend ImGui_ImplQt_Init(); @@ -39,15 +35,22 @@ public: ImGui::SetCurrentContext(context_); // Shutdown ImGui Context - ImGui_ImplOpenGL3_Shutdown(); + if (imGuiRendererInitialized_) + { + ImGui_ImplOpenGL3_Shutdown(); + } ImGui_ImplQt_Shutdown(); - ImGui::DestroyContext(context_); + + // Destroy ImGui Context + manager::ImGuiManager::Instance().DestroyContext(contextName_); } ImGuiDebugWidget* self_; ImGuiContext* context_; + std::string contextName_; bool firstRender_ {true}; + bool imGuiRendererInitialized_ {false}; }; ImGuiDebugWidget::ImGuiDebugWidget(QWidget* parent) : @@ -57,6 +60,8 @@ ImGuiDebugWidget::ImGuiDebugWidget(QWidget* parent) : setFocusPolicy(Qt::StrongFocus); } +ImGuiDebugWidget::~ImGuiDebugWidget() {} + void ImGuiDebugWidget::initializeGL() { makeCurrent(); @@ -64,6 +69,7 @@ void ImGuiDebugWidget::initializeGL() // Initialize ImGui OpenGL3 backend ImGui::SetCurrentContext(p->context_); ImGui_ImplOpenGL3_Init(); + p->imGuiRendererInitialized_ = true; } void ImGuiDebugWidget::paintGL() @@ -93,8 +99,6 @@ void ImGuiDebugWidget::paintGL() ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } -ImGuiDebugWidget::~ImGuiDebugWidget() {} - } // namespace ui } // namespace qt } // namespace scwx From 9684aa4cdc56ad46488d5a84ebfa1f8c9cb5394c Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 27 Nov 2022 23:47:55 -0600 Subject: [PATCH 6/8] Replacing ImGui Manager with ImGui Model --- scwx-qt/scwx-qt.cmake | 8 +- .../source/scwx/qt/manager/imgui_manager.cpp | 92 ------------- scwx-qt/source/scwx/qt/map/map_widget.cpp | 6 +- .../scwx/qt/model/imgui_context_model.cpp | 125 ++++++++++++++++++ .../imgui_context_model.hpp} | 27 ++-- .../source/scwx/qt/ui/imgui_debug_dialog.cpp | 4 + .../source/scwx/qt/ui/imgui_debug_widget.cpp | 7 +- 7 files changed, 156 insertions(+), 113 deletions(-) delete mode 100644 scwx-qt/source/scwx/qt/manager/imgui_manager.cpp create mode 100644 scwx-qt/source/scwx/qt/model/imgui_context_model.cpp rename scwx-qt/source/scwx/qt/{manager/imgui_manager.hpp => model/imgui_context_model.hpp} (50%) diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 688a2e7b..246432b6 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -60,14 +60,12 @@ set(HDR_GL_DRAW source/scwx/qt/gl/draw/draw_item.hpp set(SRC_GL_DRAW source/scwx/qt/gl/draw/draw_item.cpp source/scwx/qt/gl/draw/geo_line.cpp source/scwx/qt/gl/draw/rectangle.cpp) -set(HDR_MANAGER source/scwx/qt/manager/imgui_manager.hpp - source/scwx/qt/manager/radar_product_manager.hpp +set(HDR_MANAGER source/scwx/qt/manager/radar_product_manager.hpp source/scwx/qt/manager/radar_product_manager_notifier.hpp source/scwx/qt/manager/resource_manager.hpp source/scwx/qt/manager/settings_manager.hpp source/scwx/qt/manager/text_event_manager.hpp) -set(SRC_MANAGER source/scwx/qt/manager/imgui_manager.cpp - source/scwx/qt/manager/radar_product_manager.cpp +set(SRC_MANAGER source/scwx/qt/manager/radar_product_manager.cpp source/scwx/qt/manager/radar_product_manager_notifier.cpp source/scwx/qt/manager/resource_manager.cpp source/scwx/qt/manager/settings_manager.cpp @@ -95,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 diff --git a/scwx-qt/source/scwx/qt/manager/imgui_manager.cpp b/scwx-qt/source/scwx/qt/manager/imgui_manager.cpp deleted file mode 100644 index 254ec47a..00000000 --- a/scwx-qt/source/scwx/qt/manager/imgui_manager.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include - -#include - -namespace scwx -{ -namespace qt -{ -namespace manager -{ - -static const std::string logPrefix_ = "scwx::qt::manager::imgui_manager"; -static const auto logger_ = scwx::util::Logger::Create(logPrefix_); - -class ImGuiManagerImpl -{ -public: - explicit ImGuiManagerImpl() {} - - ~ImGuiManagerImpl() = default; - - std::vector contexts_ {}; -}; - -ImGuiManager::ImGuiManager() : - QObject(nullptr), p {std::make_unique()} -{ -} - -ImGuiManager::~ImGuiManager() {} - -ImGuiContext* ImGuiManager::CreateContext(const std::string& name) -{ - 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 - static size_t nextId_ {0}; - p->contexts_.emplace_back(ImGuiContextInfo {nextId_++, name, context}); - - // Inform observers contexts have been updated - emit ContextsUpdated(); - - return context; -} - -void ImGuiManager::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()) - { - // Destroy context and erase from index - ImGui::SetCurrentContext(it->context_); - ImGui::DestroyContext(); - p->contexts_.erase(it); - - // Inform observers contexts have been updated - emit ContextsUpdated(); - } -} - -std::vector ImGuiManager::contexts() const -{ - return p->contexts_; -} - -ImGuiManager& ImGuiManager::Instance() -{ - static ImGuiManager instance_; - return instance_; -} - -bool ImGuiContextInfo::operator==(const ImGuiContextInfo& o) const = default; - -} // namespace manager -} // namespace qt -} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp index be371c2d..4f015e62 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -9,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -87,7 +87,7 @@ public: static size_t currentMapId_ {0u}; imGuiContextName_ = std::format("Map {}", ++currentMapId_); imGuiContext_ = - manager::ImGuiManager::Instance().CreateContext(imGuiContextName_); + model::ImGuiContextModel::Instance().CreateContext(imGuiContextName_); // Initialize ImGui Qt backend ImGui_ImplQt_Init(); @@ -107,7 +107,7 @@ public: ImGui_ImplQt_Shutdown(); // Destroy ImGui Context - manager::ImGuiManager::Instance().DestroyContext(imGuiContextName_); + model::ImGuiContextModel::Instance().DestroyContext(imGuiContextName_); } void AddLayer(const std::string& id, 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..11a0a875 --- /dev/null +++ b/scwx-qt/source/scwx/qt/model/imgui_context_model.cpp @@ -0,0 +1,125 @@ +#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()); + } + + 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(); + } +} + +std::vector ImGuiContextModel::contexts() const +{ + return p->contexts_; +} + +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/manager/imgui_manager.hpp b/scwx-qt/source/scwx/qt/model/imgui_context_model.hpp similarity index 50% rename from scwx-qt/source/scwx/qt/manager/imgui_manager.hpp rename to scwx-qt/source/scwx/qt/model/imgui_context_model.hpp index 975a9231..7c5f4dc7 100644 --- a/scwx-qt/source/scwx/qt/manager/imgui_manager.hpp +++ b/scwx-qt/source/scwx/qt/model/imgui_context_model.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include struct ImGuiContext; @@ -11,10 +11,10 @@ namespace scwx { namespace qt { -namespace manager +namespace model { -class ImGuiManagerImpl; +class ImGuiContextModelImpl; struct ImGuiContextInfo { @@ -25,31 +25,36 @@ struct ImGuiContextInfo bool operator==(const ImGuiContextInfo& o) const; }; -class ImGuiManager : public QObject +class ImGuiContextModel : public QAbstractListModel { private: Q_OBJECT - Q_DISABLE_COPY(ImGuiManager) + Q_DISABLE_COPY(ImGuiContextModel) public: - explicit ImGuiManager(); - ~ImGuiManager(); + explicit ImGuiContextModel(); + ~ImGuiContextModel(); + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + + QVariant data(const QModelIndex& index, + int role = Qt::DisplayRole) const override; ImGuiContext* CreateContext(const std::string& name); void DestroyContext(const std::string& name); std::vector contexts() const; - static ImGuiManager& Instance(); + static ImGuiContextModel& Instance(); signals: void ContextsUpdated(); private: - friend class ImGuiManagerImpl; - std::unique_ptr p; + friend class ImGuiContextModelImpl; + std::unique_ptr p; }; -} // namespace manager +} // namespace model } // namespace qt } // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.cpp b/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.cpp index 75e90682..5ee16cde 100644 --- a/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.cpp +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.cpp @@ -1,6 +1,7 @@ #include "imgui_debug_dialog.hpp" #include "ui_imgui_debug_dialog.h" +#include #include namespace scwx @@ -33,6 +34,9 @@ ImGuiDebugDialog::ImGuiDebugDialog(QWidget* parent) : p->imGuiDebugWidget_->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding); ui->verticalLayout->insertWidget(0, p->imGuiDebugWidget_); + + // Context Combo Box + ui->contextComboBox->setModel(&model::ImGuiContextModel::Instance()); } ImGuiDebugDialog::~ImGuiDebugDialog() diff --git a/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp index dc4505f6..37cc95f1 100644 --- a/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -22,7 +22,8 @@ public: // Create ImGui Context static size_t currentIndex_ {0u}; contextName_ = std::format("ImGui Debug {}", ++currentIndex_); - context_ = manager::ImGuiManager::Instance().CreateContext(contextName_); + context_ = + model::ImGuiContextModel::Instance().CreateContext(contextName_); // Initialize ImGui Qt backend ImGui_ImplQt_Init(); @@ -42,7 +43,7 @@ public: ImGui_ImplQt_Shutdown(); // Destroy ImGui Context - manager::ImGuiManager::Instance().DestroyContext(contextName_); + model::ImGuiContextModel::Instance().DestroyContext(contextName_); } ImGuiDebugWidget* self_; From f27e2534a789ea2f35ee76e37e4587e80cce26c1 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 28 Nov 2022 00:20:31 -0600 Subject: [PATCH 7/8] Enable ImGui context selection --- .../scwx/qt/model/imgui_context_model.cpp | 28 +++++++++++++++---- .../scwx/qt/model/imgui_context_model.hpp | 4 +-- scwx-qt/source/scwx/qt/types/qt_types.hpp | 3 +- .../source/scwx/qt/ui/imgui_debug_dialog.cpp | 22 ++++++++++++++- .../source/scwx/qt/ui/imgui_debug_widget.cpp | 27 ++++++++++++++---- .../source/scwx/qt/ui/imgui_debug_widget.hpp | 6 ++++ 6 files changed, 76 insertions(+), 14 deletions(-) diff --git a/scwx-qt/source/scwx/qt/model/imgui_context_model.cpp b/scwx-qt/source/scwx/qt/model/imgui_context_model.cpp index 11a0a875..13b09198 100644 --- a/scwx-qt/source/scwx/qt/model/imgui_context_model.cpp +++ b/scwx-qt/source/scwx/qt/model/imgui_context_model.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -54,6 +55,28 @@ QVariant ImGuiContextModel::data(const QModelIndex& index, int role) const 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 {}; @@ -107,11 +130,6 @@ void ImGuiContextModel::DestroyContext(const std::string& name) } } -std::vector ImGuiContextModel::contexts() const -{ - return p->contexts_; -} - ImGuiContextModel& ImGuiContextModel::Instance() { static ImGuiContextModel instance_ {}; diff --git a/scwx-qt/source/scwx/qt/model/imgui_context_model.hpp b/scwx-qt/source/scwx/qt/model/imgui_context_model.hpp index 7c5f4dc7..7241a197 100644 --- a/scwx-qt/source/scwx/qt/model/imgui_context_model.hpp +++ b/scwx-qt/source/scwx/qt/model/imgui_context_model.hpp @@ -40,11 +40,11 @@ public: 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); - std::vector contexts() const; - static ImGuiContextModel& Instance(); signals: 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 index 5ee16cde..a416e1cd 100644 --- a/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.cpp +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_dialog.cpp @@ -2,6 +2,7 @@ #include "ui_imgui_debug_dialog.h" #include +#include #include namespace scwx @@ -36,7 +37,26 @@ ImGuiDebugDialog::ImGuiDebugDialog(QWidget* parent) : ui->verticalLayout->insertWidget(0, p->imGuiDebugWidget_); // Context Combo Box - ui->contextComboBox->setModel(&model::ImGuiContextModel::Instance()); + 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() diff --git a/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp index 37cc95f1..56d45c94 100644 --- a/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp @@ -1,6 +1,8 @@ #include #include +#include + #include #include #include @@ -24,6 +26,7 @@ public: contextName_ = std::format("ImGui Debug {}", ++currentIndex_); context_ = model::ImGuiContextModel::Instance().CreateContext(contextName_); + currentContext_ = context_; // Initialize ImGui Qt backend ImGui_ImplQt_Init(); @@ -50,8 +53,10 @@ public: ImGuiContext* context_; std::string contextName_; - bool firstRender_ {true}; - bool imGuiRendererInitialized_ {false}; + ImGuiContext* currentContext_; + + std::set renderedSet_ {}; + bool imGuiRendererInitialized_ {false}; }; ImGuiDebugWidget::ImGuiDebugWidget(QWidget* parent) : @@ -63,6 +68,17 @@ ImGuiDebugWidget::ImGuiDebugWidget(QWidget* parent) : ImGuiDebugWidget::~ImGuiDebugWidget() {} +std::string ImGuiDebugWidget::context_name() const +{ + return p->contextName_; +} + +void ImGuiDebugWidget::set_current_context(ImGuiContext* context) +{ + p->currentContext_ = context; + update(); +} + void ImGuiDebugWidget::initializeGL() { makeCurrent(); @@ -75,14 +91,14 @@ void ImGuiDebugWidget::initializeGL() void ImGuiDebugWidget::paintGL() { - ImGui::SetCurrentContext(p->context_); + ImGui::SetCurrentContext(p->currentContext_); ImGui_ImplQt_NewFrame(this); ImGui_ImplOpenGL3_NewFrame(); ImGui::NewFrame(); - if (p->firstRender_) + if (!p->renderedSet_.contains(p->currentContext_)) { // Set initial position of demo window ImGui::SetNextWindowPos(ImVec2 {width() / 2.0f, height() / 2.0f}, @@ -91,7 +107,8 @@ void ImGuiDebugWidget::paintGL() ImGui::Begin("Dear ImGui Demo"); ImGui::End(); - p->firstRender_ = false; + p->renderedSet_.insert(p->currentContext_); + update(); } ImGui::ShowDemoWindow(); diff --git a/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.hpp b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.hpp index 0294b1bd..695a6be9 100644 --- a/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.hpp +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.hpp @@ -2,6 +2,8 @@ #include +struct ImGuiContext; + namespace Ui { class ImGuiDebugWidget; @@ -25,6 +27,10 @@ public: explicit ImGuiDebugWidget(QWidget* parent = nullptr); ~ImGuiDebugWidget(); + std::string context_name() const; + + void set_current_context(ImGuiContext* context); + void initializeGL() override; void paintGL() override; From fcb89926ca1a68bcf8f2f486db1d0f81c0013f46 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 28 Nov 2022 09:23:12 -0600 Subject: [PATCH 8/8] Support events over multiple ImGui contexts --- external/imgui-backend-qt | 2 +- scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/external/imgui-backend-qt b/external/imgui-backend-qt index 0ebc0fe7..a914f181 160000 --- a/external/imgui-backend-qt +++ b/external/imgui-backend-qt @@ -1 +1 @@ -Subproject commit 0ebc0fe7fa88aa3d1eb58b2f040f11ba45227829 +Subproject commit a914f1811185f5959d50f2a199420dee4d15ae74 diff --git a/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp index 56d45c94..066ba59d 100644 --- a/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/imgui_debug_widget.cpp @@ -75,7 +75,22 @@ std::string ImGuiDebugWidget::context_name() const 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(); }