From afe20fee0e0046083cd61abe28e8f44591baf212 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 4 Apr 2021 22:16:16 -0700 Subject: [PATCH] Add Gio::Icon based RTImages --- rtgui/rtimage.cc | 102 ++++++++++++++++++++++++++++++++++++++++++++++- rtgui/rtimage.h | 8 ++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/rtgui/rtimage.cc b/rtgui/rtimage.cc index 44078ed3b..9a38c1885 100644 --- a/rtgui/rtimage.cc +++ b/rtgui/rtimage.cc @@ -22,12 +22,40 @@ #include #include +#include +#include #include "../rtengine/settings.h" namespace { +struct GIconKey { + Glib::RefPtr icon; + /** + * Icon size in pixels. + */ + int icon_size; + + GIconKey() {} + GIconKey(const Glib::RefPtr &icon, int icon_size): icon(icon), icon_size(icon_size) {} + + bool operator==(const GIconKey &other) const + { + bool icons_match = (icon.get() == nullptr && other.icon.get() == nullptr) || (icon.get() != nullptr && icon->equal(Glib::RefPtr::cast_const(other.icon))); + return icons_match && icon_size == other.icon_size; + } +}; + +struct GIconKeyHash { + size_t operator()(const GIconKey &key) const + { + const size_t icon_hash = key.icon ? key.icon->hash() : 0; + return icon_hash ^ std::hash()(key.icon_size); + } +}; + +std::unordered_map, GIconKeyHash> gIconPixbufCache; std::map > pixbufCache; std::map > surfaceCache; @@ -44,6 +72,8 @@ RTImage::RTImage (RTImage &other) : surface(other.surface), pixbuf(other.pixbuf) set(pixbuf); } else if (surface) { set(surface); + } else if (other.gIcon) { + changeImage(other.gIcon, other.gIconSize); } } @@ -80,13 +110,27 @@ RTImage::RTImage (Glib::RefPtr &other) if (other->get_surface()) { surface = other->get_surface(); set(surface); - } else { + } else if (other->pixbuf) { pixbuf = other->get_pixbuf(); set(pixbuf); + } else if (other->gIcon) { + changeImage(other->gIcon, other->gIconSize); } } } +RTImage::RTImage(const Glib::RefPtr &gIcon, Gtk::IconSize size) +{ + changeImage(gIcon, size); +} + +int RTImage::iconSizeToPixels(Gtk::IconSize size) const +{ + int width, height; + Gtk::IconSize::lookup(size, width, height); + return std::round(getTweakedDPI() / baseDPI * std::max(width, height)); +} + void RTImage::setImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName) { Glib::ustring imageName; @@ -113,10 +157,41 @@ void RTImage::setDPInScale (const double newDPI, const int newScale) } } +void RTImage::changeImage(const Glib::RefPtr &gIcon, int size) +{ + clear(); + + pixbuf.reset(); + surface.clear(); + this->gIcon = gIcon; + + if (!gIcon) { + return; + } + + gIconSize = size; + GIconKey key(gIcon, gIconSize); + auto iterator = gIconPixbufCache.find(key); + + if (iterator == gIconPixbufCache.end()) { + auto icon_pixbuf = createPixbufFromGIcon(gIcon, gIconSize); + iterator = gIconPixbufCache.emplace(key, icon_pixbuf).first; + } + + set(iterator->second); +} + +void RTImage::changeImage(const Glib::RefPtr &gIcon, Gtk::IconSize size) +{ + changeImage(gIcon, iconSizeToPixels(size)); +} + void RTImage::changeImage (const Glib::ustring& imageName) { clear (); + gIcon.reset(); + if (imageName.empty()) { return; } @@ -150,6 +225,11 @@ int RTImage::get_width() if (pixbuf) { return pixbuf->get_width(); } + + if (gIcon) { + return this->get_pixbuf()->get_width(); + } + return -1; } @@ -161,6 +241,11 @@ int RTImage::get_height() if (pixbuf) { return pixbuf->get_height(); } + + if (gIcon) { + return this->get_pixbuf()->get_height(); + } + return -1; } @@ -178,6 +263,11 @@ void RTImage::cleanup(bool all) for (auto& entry : surfaceCache) { entry.second.clear(); } + + for (auto& entry : gIconPixbufCache) { + entry.second.reset(); + } + RTScalable::cleanup(all); } @@ -189,6 +279,10 @@ void RTImage::updateImages() for (auto& entry : surfaceCache) { entry.second = createImgSurfFromFile(entry.first); } + + for (auto& entry : gIconPixbufCache) { + entry.second = createPixbufFromGIcon(entry.first.icon, entry.first.icon_size); + } } Glib::RefPtr RTImage::createPixbufFromFile (const Glib::ustring& fileName) @@ -197,6 +291,12 @@ Glib::RefPtr RTImage::createPixbufFromFile (const Glib::ustring& fi return Gdk::Pixbuf::create(imgSurf, 0, 0, imgSurf->get_width(), imgSurf->get_height()); } +Glib::RefPtr RTImage::createPixbufFromGIcon(const Glib::RefPtr &icon, int size) +{ + // TODO: Listen for theme changes and update icon, remove from cache. + return Gtk::IconTheme::get_default()->lookup_icon(icon, size, Gtk::ICON_LOOKUP_FORCE_SIZE).load_icon(); +} + Cairo::RefPtr RTImage::createImgSurfFromFile (const Glib::ustring& fileName) { Cairo::RefPtr surf; diff --git a/rtgui/rtimage.h b/rtgui/rtimage.h index eb1930d28..183a83a94 100644 --- a/rtgui/rtimage.h +++ b/rtgui/rtimage.h @@ -34,6 +34,11 @@ class RTImage final : public Gtk::Image, public RTScalable protected: Cairo::RefPtr surface; Glib::RefPtr pixbuf; + Glib::RefPtr gIcon; + int gIconSize; + + void changeImage(const Glib::RefPtr &gIcon, int size); + int iconSizeToPixels(Gtk::IconSize size) const; public: RTImage (); @@ -42,9 +47,11 @@ public: explicit RTImage (Cairo::RefPtr &surf); explicit RTImage(Cairo::RefPtr other); explicit RTImage (Glib::RefPtr &other); + explicit RTImage(const Glib::RefPtr &gIcon, Gtk::IconSize size); explicit RTImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName = Glib::ustring()); void setImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName = Glib::ustring()); + void changeImage(const Glib::RefPtr &gIcon, Gtk::IconSize size); void changeImage (const Glib::ustring& imageName); Cairo::RefPtr get_surface(); int get_width(); @@ -58,6 +65,7 @@ public: static void setScale (const int newScale); static Glib::RefPtr createPixbufFromFile (const Glib::ustring& fileName); + static Glib::RefPtr createPixbufFromGIcon(const Glib::RefPtr &icon, int size); static Cairo::RefPtr createImgSurfFromFile (const Glib::ustring& fileName); };