diff --git a/scwx-qt/source/scwx/qt/manager/font_manager.cpp b/scwx-qt/source/scwx/qt/manager/font_manager.cpp index 89a1643f..d92d3bd7 100644 --- a/scwx-qt/source/scwx/qt/manager/font_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/font_manager.cpp @@ -29,6 +29,7 @@ static const std::string logPrefix_ = "scwx::qt::manager::font_manager"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); static const std::string kFcTrueType_ {"TrueType"}; +static const std::string kFcOpenType_ {"CFF"}; struct FontRecord { @@ -70,6 +71,7 @@ public: const std::vector& GetRawFontData(const std::string& filename); + static bool CheckFontFormat(const FcChar8* format); static FontRecord MatchFontFile(const std::string& family, const std::vector& styles); @@ -457,6 +459,13 @@ void FontManager::Impl::FinalizeFontconfig() FcFini(); } +bool FontManager::Impl::CheckFontFormat(const FcChar8* format) +{ + const std::string stdFormat = reinterpret_cast(format); + + return stdFormat == kFcTrueType_ || stdFormat == kFcOpenType_; +} + FontRecord FontManager::Impl::MatchFontFile(const std::string& family, const std::vector& styles) @@ -469,9 +478,6 @@ FontManager::Impl::MatchFontFile(const std::string& family, FcPatternAddString( pattern, FC_FAMILY, reinterpret_cast(family.c_str())); - FcPatternAddString(pattern, - FC_FONTFORMAT, - reinterpret_cast(kFcTrueType_.c_str())); FcPatternAddBool(pattern, FC_SYMBOL, FcFalse); if (!styles.empty()) @@ -505,6 +511,7 @@ FontManager::Impl::MatchFontFile(const std::string& family, FcChar8* fcFamily = nullptr; FcChar8* fcStyle = nullptr; FcChar8* fcFile = nullptr; + FcChar8* fcFormat = nullptr; FcBool fcSymbol = FcFalse; // Match was found, get properties @@ -515,7 +522,10 @@ FontManager::Impl::MatchFontFile(const std::string& family, FcPatternGetString(match, FC_FILE, 0, &fcFile) == FcResultMatch && FcPatternGetBool(match, FC_SYMBOL, 0, &fcSymbol) == FcResultMatch && - fcSymbol == FcFalse /*Must check fcSymbol manually*/) + FcPatternGetString(match, FC_FONTFORMAT, 0, &fcFormat) == + FcResultMatch && + fcSymbol == FcFalse /*Must check fcSymbol manually*/ && + CheckFontFormat(fcFormat)) { record.family_ = reinterpret_cast(fcFamily); record.style_ = reinterpret_cast(fcStyle); diff --git a/scwx-qt/source/scwx/qt/map/alert_layer.cpp b/scwx-qt/source/scwx/qt/map/alert_layer.cpp index c88f6220..7c5c9db2 100644 --- a/scwx-qt/source/scwx/qt/map/alert_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/alert_layer.cpp @@ -229,7 +229,10 @@ public: AlertLayer::AlertLayer(std::shared_ptr context, awips::Phenomenon phenomenon) : - DrawLayer(context), p(std::make_unique(this, context, phenomenon)) + DrawLayer( + context, + fmt::format("AlertLayer {}", awips::GetPhenomenonText(phenomenon))), + p(std::make_unique(this, context, phenomenon)) { for (auto alertActive : {false, true}) { diff --git a/scwx-qt/source/scwx/qt/map/draw_layer.cpp b/scwx-qt/source/scwx/qt/map/draw_layer.cpp index 7d03d13a..13d06780 100644 --- a/scwx-qt/source/scwx/qt/map/draw_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/draw_layer.cpp @@ -1,12 +1,17 @@ +#include +#include #include +#include #include #include -namespace scwx -{ -namespace qt -{ -namespace map +#include +#include +#include +#include +#include + +namespace scwx::qt::map { static const std::string logPrefix_ = "scwx::qt::map::draw_layer"; @@ -15,21 +20,57 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_); class DrawLayerImpl { public: - explicit DrawLayerImpl(std::shared_ptr context) : - context_ {context}, drawList_ {}, textureAtlas_ {GL_INVALID_INDEX} + explicit DrawLayerImpl(std::shared_ptr context, + const std::string& imGuiContextName) : + context_ {std::move(context)}, drawList_ {} { + static size_t currentLayerId_ {0u}; + imGuiContextName_ = + fmt::format("{} {}", imGuiContextName, ++currentLayerId_); + // This must be initialized after the last line + // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) + imGuiContext_ = + model::ImGuiContextModel::Instance().CreateContext(imGuiContextName_); + + // Initialize ImGui Qt backend + ImGui_ImplQt_Init(); } - ~DrawLayerImpl() {} + ~DrawLayerImpl() + { + // 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_); + } + + DrawLayerImpl(const DrawLayerImpl&) = delete; + DrawLayerImpl& operator=(const DrawLayerImpl&) = delete; + DrawLayerImpl(const DrawLayerImpl&&) = delete; + DrawLayerImpl& operator=(const DrawLayerImpl&&) = delete; std::shared_ptr context_; std::vector> drawList_; - GLuint textureAtlas_; + GLuint textureAtlas_ {GL_INVALID_INDEX}; std::uint64_t textureAtlasBuildCount_ {}; + + std::string imGuiContextName_; + ImGuiContext* imGuiContext_; + bool imGuiRendererInitialized_ {}; }; -DrawLayer::DrawLayer(const std::shared_ptr& context) : - GenericLayer(context), p(std::make_unique(context)) +DrawLayer::DrawLayer(const std::shared_ptr& context, + const std::string& imGuiContextName) : + GenericLayer(context), + p(std::make_unique(context, imGuiContextName)) { } DrawLayer::~DrawLayer() = default; @@ -42,9 +83,45 @@ void DrawLayer::Initialize() { item->Initialize(); } + + ImGuiInitialize(); } -void DrawLayer::Render(const QMapLibre::CustomLayerRenderParameters& params) +void DrawLayer::ImGuiFrameStart() +{ + auto defaultFont = manager::FontManager::Instance().GetImGuiFont( + types::FontCategory::Default); + + // Setup ImGui Frame + ImGui::SetCurrentContext(p->imGuiContext_); + + // Start ImGui Frame + ImGui_ImplQt_NewFrame(p->context_->widget()); + ImGui_ImplOpenGL3_NewFrame(); + ImGui::NewFrame(); + ImGui::PushFont(defaultFont->font()); +} + +void DrawLayer::ImGuiFrameEnd() +{ + // Pop default font + ImGui::PopFont(); + + // Render ImGui Frame + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); +} + +void DrawLayer::ImGuiInitialize() +{ + ImGui::SetCurrentContext(p->imGuiContext_); + ImGui_ImplQt_RegisterWidget(p->context_->widget()); + ImGui_ImplOpenGL3_Init(); + p->imGuiRendererInitialized_ = true; +} + +void DrawLayer::RenderWithoutImGui( + const QMapLibre::CustomLayerRenderParameters& params) { gl::OpenGLFunctions& gl = p->context_->gl(); p->textureAtlas_ = p->context_->GetTextureAtlas(); @@ -68,6 +145,17 @@ void DrawLayer::Render(const QMapLibre::CustomLayerRenderParameters& params) p->textureAtlasBuildCount_ = newTextureAtlasBuildCount; } +void DrawLayer::ImGuiSelectContext() +{ + ImGui::SetCurrentContext(p->imGuiContext_); +} + +void DrawLayer::Render(const QMapLibre::CustomLayerRenderParameters& params) +{ + ImGuiFrameStart(); + RenderWithoutImGui(params); + ImGuiFrameEnd(); +} void DrawLayer::Deinitialize() { @@ -90,15 +178,15 @@ bool DrawLayer::RunMousePicking( bool itemPicked = false; // For each draw item in the draw list in reverse - for (auto it = p->drawList_.rbegin(); it != p->drawList_.rend(); ++it) + for (auto& it : std::ranges::reverse_view(p->drawList_)) { // Run mouse picking on each draw item - if ((*it)->RunMousePicking(params, - mouseLocalPos, - mouseGlobalPos, - mouseCoords, - mouseGeoCoords, - eventHandler)) + if (it->RunMousePicking(params, + mouseLocalPos, + mouseGlobalPos, + mouseCoords, + mouseGeoCoords, + eventHandler)) { // If a draw item was picked, don't process additional items itemPicked = true; @@ -114,6 +202,4 @@ void DrawLayer::AddDrawItem(const std::shared_ptr& drawItem) p->drawList_.push_back(drawItem); } -} // namespace map -} // namespace qt -} // namespace scwx +} // namespace scwx::qt::map diff --git a/scwx-qt/source/scwx/qt/map/draw_layer.hpp b/scwx-qt/source/scwx/qt/map/draw_layer.hpp index 22dfa76c..6cfa5aae 100644 --- a/scwx-qt/source/scwx/qt/map/draw_layer.hpp +++ b/scwx-qt/source/scwx/qt/map/draw_layer.hpp @@ -15,7 +15,8 @@ class DrawLayerImpl; class DrawLayer : public GenericLayer { public: - explicit DrawLayer(const std::shared_ptr& context); + explicit DrawLayer(const std::shared_ptr& context, + const std::string& imGuiContextName); virtual ~DrawLayer(); virtual void Initialize() override; @@ -32,6 +33,12 @@ public: protected: void AddDrawItem(const std::shared_ptr& drawItem); + void ImGuiFrameStart(); + void ImGuiFrameEnd(); + void ImGuiInitialize(); + void + RenderWithoutImGui(const QMapLibre::CustomLayerRenderParameters& params); + void ImGuiSelectContext(); private: std::unique_ptr p; diff --git a/scwx-qt/source/scwx/qt/map/map_context.cpp b/scwx-qt/source/scwx/qt/map/map_context.cpp index 38a41e1f..46c2b6fa 100644 --- a/scwx-qt/source/scwx/qt/map/map_context.cpp +++ b/scwx-qt/source/scwx/qt/map/map_context.cpp @@ -36,6 +36,8 @@ public: std::shared_ptr overlayProductView_ {nullptr}; std::shared_ptr radarProductView_; + + QWidget* widget_; }; MapContext::MapContext( @@ -109,6 +111,11 @@ int16_t MapContext::radar_product_code() const return p->radarProductCode_; } +QWidget* MapContext::widget() const +{ + return p->widget_; +} + void MapContext::set_map(const std::shared_ptr& map) { p->map_ = map; @@ -167,6 +174,11 @@ void MapContext::set_radar_product_code(int16_t radarProductCode) p->radarProductCode_ = radarProductCode; } +void MapContext::set_widget(QWidget* widget) +{ + p->widget_ = widget; +} + } // namespace map } // namespace qt } // namespace scwx diff --git a/scwx-qt/source/scwx/qt/map/map_context.hpp b/scwx-qt/source/scwx/qt/map/map_context.hpp index 59fb8a5b..680f9ddd 100644 --- a/scwx-qt/source/scwx/qt/map/map_context.hpp +++ b/scwx-qt/source/scwx/qt/map/map_context.hpp @@ -38,18 +38,21 @@ public: MapContext(MapContext&&) noexcept; MapContext& operator=(MapContext&&) noexcept; - std::weak_ptr map() const; - std::string map_copyrights() const; - MapProvider map_provider() const; - MapSettings& settings(); - QMargins color_table_margins() const; - float pixel_ratio() const; - common::Coordinate mouse_coordinate() const; - std::shared_ptr overlay_product_view() const; - std::shared_ptr radar_product_view() const; - common::RadarProductGroup radar_product_group() const; - std::string radar_product() const; - int16_t radar_product_code() const; + [[nodiscard]] std::weak_ptr map() const; + [[nodiscard]] std::string map_copyrights() const; + [[nodiscard]] MapProvider map_provider() const; + [[nodiscard]] MapSettings& settings(); + [[nodiscard]] QMargins color_table_margins() const; + [[nodiscard]] float pixel_ratio() const; + [[nodiscard]] common::Coordinate mouse_coordinate() const; + [[nodiscard]] std::shared_ptr + overlay_product_view() const; + [[nodiscard]] std::shared_ptr + radar_product_view() const; + [[nodiscard]] common::RadarProductGroup radar_product_group() const; + [[nodiscard]] std::string radar_product() const; + [[nodiscard]] int16_t radar_product_code() const; + [[nodiscard]] QWidget* widget() const; void set_map(const std::shared_ptr& map); void set_map_copyrights(const std::string& copyrights); @@ -64,6 +67,7 @@ public: void set_radar_product_group(common::RadarProductGroup radarProductGroup); void set_radar_product(const std::string& radarProduct); void set_radar_product_code(int16_t radarProductCode); + void set_widget(QWidget* widget); private: class Impl; diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp index 466a03fe..f2599579 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -114,6 +114,7 @@ public: context_->set_map_provider( GetMapProvider(generalSettings.map_provider().GetValue())); context_->set_overlay_product_view(overlayProductView); + context_->set_widget(widget); // Initialize map data SetRadarSite(generalSettings.default_radar_site().GetValue()); @@ -1571,21 +1572,13 @@ void MapWidget::paintGL() // Handle hotkey updates p->HandleHotkeyUpdates(); - // Setup ImGui Frame - ImGui::SetCurrentContext(p->imGuiContext_); - // Lock ImGui font atlas prior to new ImGui frame std::shared_lock imguiFontAtlasLock { manager::FontManager::Instance().imgui_font_atlas_mutex()}; - // Start ImGui Frame - ImGui_ImplQt_NewFrame(this); - ImGui_ImplOpenGL3_NewFrame(); + // Check ImGui fonts + ImGui::SetCurrentContext(p->imGuiContext_); p->ImGuiCheckFonts(); - ImGui::NewFrame(); - - // Set default font - ImGui::PushFont(defaultFont->font()); // Update pixel ratio p->context_->set_pixel_ratio(pixelRatio()); @@ -1596,6 +1589,18 @@ void MapWidget::paintGL() size() * pixelRatio()); p->map_->render(); + // ImGui tool tip code + // Setup ImGui Frame + ImGui::SetCurrentContext(p->imGuiContext_); + + // Start ImGui Frame + ImGui_ImplQt_NewFrame(this); + ImGui_ImplOpenGL3_NewFrame(); + ImGui::NewFrame(); + + // Set default font + ImGui::PushFont(defaultFont->font()); + // Perform mouse picking if (p->hasMouse_) { diff --git a/scwx-qt/source/scwx/qt/map/marker_layer.cpp b/scwx-qt/source/scwx/qt/map/marker_layer.cpp index 39e43a57..aec23f84 100644 --- a/scwx-qt/source/scwx/qt/map/marker_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/marker_layer.cpp @@ -129,7 +129,8 @@ void MarkerLayer::Impl::ReloadMarkers() } MarkerLayer::MarkerLayer(const std::shared_ptr& context) : - DrawLayer(context), p(std::make_unique(this, context)) + DrawLayer(context, "MarkerLayer"), + p(std::make_unique(this, context)) { AddDrawItem(p->geoIcons_); } diff --git a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp index da82ef7f..3522ba40 100644 --- a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp @@ -143,7 +143,8 @@ public: }; OverlayLayer::OverlayLayer(std::shared_ptr context) : - DrawLayer(context), p(std::make_unique(this, context)) + DrawLayer(context, "OverlayLayer"), + p(std::make_unique(this, context)) { AddDrawItem(p->activeBoxOuter_); AddDrawItem(p->activeBoxInner_); @@ -292,6 +293,8 @@ void OverlayLayer::Render(const QMapLibre::CustomLayerRenderParameters& params) auto& settings = context()->settings(); const float pixelRatio = context()->pixel_ratio(); + ImGuiFrameStart(); + p->sweepTimePicked_ = false; if (radarProductView != nullptr) @@ -457,7 +460,7 @@ void OverlayLayer::Render(const QMapLibre::CustomLayerRenderParameters& params) p->icons_->SetIconVisible(p->mapLogoIcon_, generalSettings.show_map_logo().GetValue()); - DrawLayer::Render(params); + DrawLayer::RenderWithoutImGui(params); auto mapCopyrights = context()->map_copyrights(); if (mapCopyrights.length() > 0 && @@ -491,6 +494,8 @@ void OverlayLayer::Render(const QMapLibre::CustomLayerRenderParameters& params) p->lastFontSize_ = ImGui::GetFontSize(); p->lastColorTableMargins_ = colorTableMargins; + ImGuiFrameEnd(); + SCWX_GL_CHECK_ERROR(); } diff --git a/scwx-qt/source/scwx/qt/map/overlay_product_layer.cpp b/scwx-qt/source/scwx/qt/map/overlay_product_layer.cpp index 64745fd5..76eeaa8b 100644 --- a/scwx-qt/source/scwx/qt/map/overlay_product_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/overlay_product_layer.cpp @@ -109,7 +109,8 @@ public: }; OverlayProductLayer::OverlayProductLayer(std::shared_ptr context) : - DrawLayer(context), p(std::make_unique(this, context)) + DrawLayer(context, "OverlayProductLayer"), + p(std::make_unique(this, context)) { auto overlayProductView = context->overlay_product_view(); connect(overlayProductView.get(), diff --git a/scwx-qt/source/scwx/qt/map/placefile_layer.cpp b/scwx-qt/source/scwx/qt/map/placefile_layer.cpp index be2d9a18..df9828eb 100644 --- a/scwx-qt/source/scwx/qt/map/placefile_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/placefile_layer.cpp @@ -66,7 +66,7 @@ public: PlacefileLayer::PlacefileLayer(const std::shared_ptr& context, const std::string& placefileName) : - DrawLayer(context), + DrawLayer(context, fmt::format("PlacefileLayer {}", placefileName)), p(std::make_unique(this, context, placefileName)) { AddDrawItem(p->placefileImages_); diff --git a/scwx-qt/source/scwx/qt/map/radar_site_layer.cpp b/scwx-qt/source/scwx/qt/map/radar_site_layer.cpp index d2fd7547..65b53f14 100644 --- a/scwx-qt/source/scwx/qt/map/radar_site_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/radar_site_layer.cpp @@ -44,7 +44,7 @@ public: }; RadarSiteLayer::RadarSiteLayer(std::shared_ptr context) : - DrawLayer(context), p(std::make_unique(this)) + DrawLayer(context, "RadarSiteLayer"), p(std::make_unique(this)) { } @@ -55,6 +55,8 @@ void RadarSiteLayer::Initialize() logger_->debug("Initialize()"); p->radarSites_ = config::RadarSite::GetAll(); + + ImGuiInitialize(); } void RadarSiteLayer::Render( @@ -84,6 +86,7 @@ void RadarSiteLayer::Render( p->halfWidth_ = params.width * 0.5f; p->halfHeight_ = params.height * 0.5f; + ImGuiFrameStart(); // Radar site ImGui windows shouldn't have padding ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2 {0.0f, 0.0f}); @@ -93,6 +96,7 @@ void RadarSiteLayer::Render( } ImGui::PopStyleVar(); + ImGuiFrameEnd(); SCWX_GL_CHECK_ERROR(); } @@ -136,6 +140,7 @@ void RadarSiteLayer::Impl::RenderRadarSite( if (ImGui::Button(radarSite->id().c_str())) { Q_EMIT self_->RadarSiteSelected(radarSite->id()); + self_->ImGuiSelectContext(); } // Store hover text for mouse picking pass