From 1c859262001c7865946739baa8414c5369f45031 Mon Sep 17 00:00:00 2001 From: Pandagrapher Date: Fri, 2 Sep 2022 19:15:42 +0200 Subject: [PATCH] Creates an RTImage cache Fixes: - Fixes GUI issue on Windows (GDI handles limit reached) - Fixes an incorrect icon name in Perspective tool - Adds robustness RTScalable::loadSurfaceFromIcon function --- rtgui/perspective.cc | 2 +- rtgui/rtimage.cc | 82 +++++++++++++++++++++++++++++++++++++++++--- rtgui/rtimage.h | 18 +++++++++- rtgui/rtscalable.cc | 16 +++++++-- rtgui/rtsurface.cc | 32 ++++++++++------- rtgui/rtsurface.h | 1 + 6 files changed, 130 insertions(+), 21 deletions(-) diff --git a/rtgui/perspective.cc b/rtgui/perspective.cc index 83b6c660f..af182617e 100644 --- a/rtgui/perspective.cc +++ b/rtgui/perspective.cc @@ -120,7 +120,7 @@ PerspCorrection::PerspCorrection () : FoldableToolPanel(this, "perspective", M(" RTImage* const ipersVL = Gtk::manage (new RTImage ("perspective-vertical-bottom-small")); RTImage* const ipersVR = Gtk::manage (new RTImage ("perspective-vertical-top-small")); - RTImage* const ipers_auto_pitch = Gtk::manage (new RTImage ("perspective-vertical-botton", Gtk::ICON_SIZE_BUTTON)); + RTImage* const ipers_auto_pitch = Gtk::manage (new RTImage ("perspective-vertical-bottom", Gtk::ICON_SIZE_BUTTON)); RTImage* const ipers_auto_yaw = Gtk::manage (new RTImage ("perspective-horizontal-left", Gtk::ICON_SIZE_BUTTON)); RTImage* const ipers_auto_pitch_yaw = Gtk::manage (new RTImage ("perspective-horizontal-vertical", Gtk::ICON_SIZE_BUTTON)); diff --git a/rtgui/rtimage.cc b/rtgui/rtimage.cc index 2040ec21d..6096b9251 100644 --- a/rtgui/rtimage.cc +++ b/rtgui/rtimage.cc @@ -21,21 +21,95 @@ #include "rtimage.h" +#include "rtsurface.h" + +std::map, std::shared_ptr> RTImageCache::cache; + +std::shared_ptr RTImageCache::getCachedSurface(const Glib::ustring &icon_name, const Gtk::IconSize icon_size) +{ + // Look for an existing cached icon + const auto key = std::pair(icon_name, icon_size); + const auto item = cache.find(key); + + if (item != cache.end()) { // A cached icon exists + return item->second; + } else { // Create the icon + auto surface = std::shared_ptr(new RTSurface(icon_name, icon_size)); + + // Add the surface to the cache if the icon exist + if (surface) { + cache.insert({key, surface}); + } + + return surface; + } +} + +void RTImageCache::updateCache() +{ + // Iterate over cache to updated RTSurface + for (auto const& item : cache) { + item.second->updateSurface(); + } +} + RTImage::RTImage () {} RTImage::RTImage (const Glib::ustring& iconName, const Gtk::IconSize iconSize) : - Gtk::Image(iconName, iconSize), - size(iconSize) + Gtk::Image(), + size(iconSize), + icon_name(iconName) { + // Set surface from icon cache + surface = RTImageCache::getCachedSurface(this->icon_name, this->size); + + // Add it to the RTImage if surface exists + if (surface) { + set(surface->get()); + } } void RTImage::set_from_icon_name(const Glib::ustring& iconName) { - Gtk::Image::set_from_icon_name(iconName, this->size); + this->icon_name = iconName; + + // Set surface from icon cache + surface = RTImageCache::getCachedSurface(this->icon_name, this->size); + + // Add it to the RTImage if surface exists + if (surface) { + set(surface->get()); + } } void RTImage::set_from_icon_name(const Glib::ustring& iconName, const Gtk::IconSize iconSize) { + this->icon_name = iconName; this->size = iconSize; - Gtk::Image::set_from_icon_name(iconName, this->size); + + // Set surface from icon cache + surface = RTImageCache::getCachedSurface(this->icon_name, this->size); + + // Add it to the RTImage if surface exists + if (surface) { + set(surface->get()); + } +} + +int RTImage::get_width() +{ + if (surface) { + return surface->getWidth(); + } + + return -1; +} + +int RTImage::get_height() +{ + if (surface) { + return surface->getHeight(); + } + + return -1; } diff --git a/rtgui/rtimage.h b/rtgui/rtimage.h index 895267dbd..0908683c8 100644 --- a/rtgui/rtimage.h +++ b/rtgui/rtimage.h @@ -20,7 +20,18 @@ */ #pragma once -#include +#include + +class RTSurface; +class RTImageCache final +{ +private: + static std::map, std::shared_ptr> cache; + +public: + static std::shared_ptr getCachedSurface(const Glib::ustring &icon_name, const Gtk::IconSize icon_size); + static void updateCache(); +}; /** * @brief A derived class of Gtk::Image in order to handle theme-related icon sets. @@ -29,6 +40,8 @@ class RTImage final : public Gtk::Image { private: Gtk::IconSize size; + Glib::ustring icon_name; + std::shared_ptr surface; public: RTImage (); @@ -36,4 +49,7 @@ public: void set_from_icon_name(const Glib::ustring& iconName); void set_from_icon_name(const Glib::ustring& iconName, const Gtk::IconSize iconSize); + + int get_width(); + int get_height(); }; diff --git a/rtgui/rtscalable.cc b/rtgui/rtscalable.cc index 26ea0542e..586d38dfa 100644 --- a/rtgui/rtscalable.cc +++ b/rtgui/rtscalable.cc @@ -68,10 +68,22 @@ Cairo::RefPtr RTScalable::loadSurfaceFromIcon(const Glib::u // Looking for corresponding icon (if existing) const auto iconInfo = theme->lookup_icon(iconName, size); + + if (!iconInfo) { + if (rtengine::settings->verbose) { + std::cerr << "Failed to load icon \"" << iconName << "\" for size " << size << "px" << std::endl; + } + + return surf; + } + const auto iconPath = iconInfo.get_filename(); - if ((iconPath.empty() || !iconInfo) && rtengine::settings->verbose) { - std::cerr << "Failed to load icon \"" << iconName << "\" for size " << size << "px" << std::endl; + if (iconPath.empty()) { + if (rtengine::settings->verbose) { + std::cerr << "Failed to load icon \"" << iconName << "\" for size " << size << "px" << std::endl; + } + return surf; } diff --git a/rtgui/rtsurface.cc b/rtgui/rtsurface.cc index dccb3271c..d26f2cb02 100644 --- a/rtgui/rtsurface.cc +++ b/rtgui/rtsurface.cc @@ -161,19 +161,7 @@ Cairo::RefPtr RTSurface::get() { if (dpiBack != RTScalable::getDPI() || scaleBack != RTScalable::getScale()) { - switch (type) { - case RTSurface::IconType : - surface = RTScalable::loadSurfaceFromIcon(name, icon_size); - break; - case RTSurface::PNGType : - surface = RTScalable::loadSurfaceFromPNG(name); - break; - case RTSurface::SVGType : - surface = RTScalable::loadSurfaceFromSVG(name); - break; - default : - break; - } + updateSurface(); // Save new DPI and scale dpiBack = RTScalable::getDPI(); @@ -182,3 +170,21 @@ Cairo::RefPtr RTSurface::get() return surface; } + +void RTSurface::updateSurface() +{ + // Update surface based on the scale + switch (type) { + case RTSurface::IconType : + surface = RTScalable::loadSurfaceFromIcon(name, icon_size); + break; + case RTSurface::PNGType : + surface = RTScalable::loadSurfaceFromPNG(name); + break; + case RTSurface::SVGType : + surface = RTScalable::loadSurfaceFromSVG(name); + break; + default : + break; + } +} diff --git a/rtgui/rtsurface.h b/rtgui/rtsurface.h index e58c1b206..629a07a83 100644 --- a/rtgui/rtsurface.h +++ b/rtgui/rtsurface.h @@ -52,4 +52,5 @@ public: bool hasSurface(); Cairo::RefPtr get(); + void updateSurface(); };