diff options
author | ouwou <26526779+ouwou@users.noreply.github.com> | 2021-01-16 23:49:27 -0500 |
---|---|---|
committer | ouwou <26526779+ouwou@users.noreply.github.com> | 2021-01-16 23:49:27 -0500 |
commit | 3f6024ddf213b83cf0c815b68f8ad8de3f3afa44 (patch) | |
tree | c0f172c0d6af12250f20279c4ffff59c4895c47a /components | |
parent | 3a25249a0dc5b8ebbb7039da2af9fefb69fcf04d (diff) | |
download | abaddon-portaudio-3f6024ddf213b83cf0c815b68f8ad8de3f3afa44.tar.gz abaddon-portaudio-3f6024ddf213b83cf0c815b68f8ad8de3f3afa44.zip |
improve image loading a bit (close #6)
Diffstat (limited to 'components')
-rw-r--r-- | components/chatmessage.cpp | 68 | ||||
-rw-r--r-- | components/chatmessage.hpp | 17 | ||||
-rw-r--r-- | components/chatwindow.cpp | 10 | ||||
-rw-r--r-- | components/lazyimage.cpp | 41 | ||||
-rw-r--r-- | components/lazyimage.hpp | 20 | ||||
-rw-r--r-- | components/memberlist.cpp | 21 | ||||
-rw-r--r-- | components/memberlist.hpp | 3 |
7 files changed, 78 insertions, 102 deletions
diff --git a/components/chatmessage.cpp b/components/chatmessage.cpp index 40d706b..4692a80 100644 --- a/components/chatmessage.cpp +++ b/components/chatmessage.cpp @@ -1,6 +1,7 @@ #include "chatmessage.hpp" #include "../abaddon.hpp" #include "../util.hpp" +#include "lazyimage.hpp" #include <unordered_map> constexpr const int EmojiSize = 24; // settings eventually @@ -116,35 +117,11 @@ void ChatMessageItemContainer::UpdateContent() { if (data->Embeds.size() == 1) { m_embed_component = CreateEmbedComponent(data->Embeds[0]); - if (m_embed_imgurl.size() > 0) { - m_signal_image_load.emit(m_embed_imgurl); - } AttachEventHandlers(*m_embed_component); m_main->add(*m_embed_component); } } -void ChatMessageItemContainer::UpdateImage(std::string url, Glib::RefPtr<Gdk::Pixbuf> buf) { - if (!buf) return; - - if (m_embed_img != nullptr && m_embed_imgurl == url) { - int w, h; - m_embed_img->get_size_request(w, h); - m_embed_img->property_pixbuf() = buf->scale_simple(w, h, Gdk::INTERP_BILINEAR); - - return; - } - - auto it = m_img_loadmap.find(url); - if (it != m_img_loadmap.end()) { - const auto inw = it->second.second.first; - const auto inh = it->second.second.second; - int w, h; - GetImageDimensions(inw, inh, w, h); - it->second.first->property_pixbuf() = buf->scale_simple(w, h, Gdk::INTERP_BILINEAR); - } -} - void ChatMessageItemContainer::UpdateReactions() { if (m_reactions_component != nullptr) delete m_reactions_component; @@ -179,11 +156,6 @@ void ChatMessageItemContainer::UpdateAttributes() { m_attrib_label->set_markup("<span color='#999999'>[edited]</span>"); } -bool ChatMessageItemContainer::EmitImageLoad(std::string url) { - m_signal_image_load.emit(url); - return false; -} - void ChatMessageItemContainer::AddClickHandler(Gtk::Widget *widget, std::string url) { // clang-format off widget->signal_button_press_event().connect([url](GdkEventButton *event) -> bool { @@ -351,24 +323,23 @@ Gtk::Widget *ChatMessageItemContainer::CreateEmbedComponent(const EmbedData &emb bool is_img = embed.Image.has_value() && embed.Image->ProxyURL.has_value(); bool is_thumb = embed.Thumbnail.has_value() && embed.Thumbnail->ProxyURL.has_value(); if (is_img || is_thumb) { - auto *img = Gtk::manage(new Gtk::Image); - img->set_halign(Gtk::ALIGN_CENTER); - img->set_margin_top(5); int w = 0, h = 0; if (is_img) GetImageDimensions(*embed.Image->Width, *embed.Image->Height, w, h, EmbedImageWidth, EmbedImageHeight); else GetImageDimensions(*embed.Thumbnail->Width, *embed.Thumbnail->Height, w, h, EmbedImageWidth, EmbedImageHeight); - img->set_size_request(w, h); - main->pack_start(*img); - m_embed_img = img; + + std::string url; if (is_img) - m_embed_imgurl = *embed.Image->ProxyURL; + url = *embed.Image->ProxyURL; else - m_embed_imgurl = *embed.Thumbnail->ProxyURL; + url = *embed.Thumbnail->ProxyURL; - Abaddon::Get().GetImageManager().LoadFromURL(m_embed_imgurl, - sigc::mem_fun(*this, &ChatMessageItemContainer::OnEmbedImageLoad)); + auto *img = Gtk::manage(new LazyImage(url, w, h, false)); + img->set_halign(Gtk::ALIGN_CENTER); + img->set_margin_top(5); + img->set_size_request(w, h); + main->pack_start(*img); } if (embed.Footer.has_value()) { @@ -410,14 +381,13 @@ Gtk::Widget *ChatMessageItemContainer::CreateImageComponent(const std::string &p GetImageDimensions(inw, inh, w, h); Gtk::EventBox *ev = Gtk::manage(new Gtk::EventBox); - Gtk::Image *widget = Gtk::manage(new Gtk::Image); + Gtk::Image *widget = Gtk::manage(new LazyImage(proxy_url, w, h, false)); ev->add(*widget); widget->set_halign(Gtk::ALIGN_START); widget->set_size_request(w, h); AttachEventHandlers(*ev); AddClickHandler(ev, url); - HandleImage(w, h, *widget, proxy_url); return ev; } @@ -608,18 +578,6 @@ void ChatMessageItemContainer::ReactionUpdateImage(Gtk::Image *img, const Glib:: img->property_pixbuf() = pb->scale_simple(16, 16, Gdk::INTERP_BILINEAR); } -void ChatMessageItemContainer::HandleImage(int w, int h, Gtk::Image &img, std::string url) { - m_img_loadmap[url] = { &img, { w, h } }; - // ask the chatwindow to call UpdateImage because dealing with lifetimes sucks - Glib::signal_idle().connect(sigc::bind(sigc::mem_fun(*this, &ChatMessageItemContainer::EmitImageLoad), url)); -} - -void ChatMessageItemContainer::OnEmbedImageLoad(const Glib::RefPtr<Gdk::Pixbuf> &pixbuf) { - int w, h; - m_embed_img->get_size_request(w, h); - m_embed_img->property_pixbuf() = pixbuf->scale_simple(w, h, Gdk::INTERP_BILINEAR); -} - Glib::ustring ChatMessageItemContainer::GetText(const Glib::RefPtr<Gtk::TextBuffer> &buf) { Gtk::TextBuffer::iterator a, b; buf->get_bounds(a, b); @@ -986,10 +944,6 @@ ChatMessageItemContainer::type_signal_action_reaction_remove ChatMessageItemCont return m_signal_action_reaction_remove; } -ChatMessageItemContainer::type_signal_image_load ChatMessageItemContainer::signal_image_load() { - return m_signal_image_load; -} - void ChatMessageItemContainer::AttachEventHandlers(Gtk::Widget &widget) { const auto on_button_press_event = [this](GdkEventButton *event) -> bool { if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_SECONDARY) { diff --git a/components/chatmessage.hpp b/components/chatmessage.hpp index 92eb8af..43bf7a2 100644 --- a/components/chatmessage.hpp +++ b/components/chatmessage.hpp @@ -13,12 +13,9 @@ public: // attributes = edited, deleted void UpdateAttributes(); void UpdateContent(); - void UpdateImage(std::string url, Glib::RefPtr<Gdk::Pixbuf> buf); void UpdateReactions(); protected: - bool EmitImageLoad(std::string url); - void AddClickHandler(Gtk::Widget *widget, std::string); Gtk::TextView *CreateTextComponent(const Message *data); // Message.Content void UpdateTextComponent(Gtk::TextView *tv); @@ -29,9 +26,6 @@ protected: Gtk::Widget *CreateReactionsComponent(const Message &data); Gtk::Widget *CreateReplyComponent(const Message &data); void ReactionUpdateImage(Gtk::Image *img, const Glib::RefPtr<Gdk::Pixbuf> &pb); - void HandleImage(int w, int h, Gtk::Image &img, std::string url); - - void OnEmbedImageLoad(const Glib::RefPtr<Gdk::Pixbuf> &pixbuf); static Glib::ustring GetText(const Glib::RefPtr<Gtk::TextBuffer> &buf); @@ -59,8 +53,6 @@ protected: std::map<Glib::RefPtr<Gtk::TextTag>, std::string> m_link_tagmap; std::map<Glib::RefPtr<Gtk::TextTag>, Snowflake> m_channel_tagmap; - std::unordered_map<std::string, std::pair<Gtk::Image *, std::pair<int, int>>> m_img_loadmap; // url -> [img, [w, h]] - void AttachEventHandlers(Gtk::Widget &widget); void ShowMenu(GdkEvent *event); @@ -78,16 +70,12 @@ protected: Gtk::EventBox *m_ev; Gtk::Box *m_main; Gtk::Label *m_attrib_label = nullptr; - Gtk::Image *m_embed_img = nullptr; // yes this is hacky no i dont care (for now) - std::string m_embed_imgurl; Gtk::TextView *m_text_component = nullptr; Gtk::Widget *m_embed_component = nullptr; Gtk::Widget *m_reactions_component = nullptr; public: - typedef sigc::signal<void, std::string> type_signal_image_load; - typedef sigc::signal<void> type_signal_action_delete; typedef sigc::signal<void> type_signal_action_edit; typedef sigc::signal<void, Snowflake> type_signal_channel_click; @@ -101,17 +89,12 @@ public: type_signal_channel_click signal_action_channel_click(); type_signal_action_reaction_add signal_action_reaction_add(); type_signal_action_reaction_remove signal_action_reaction_remove(); - - type_signal_image_load signal_image_load(); - private: type_signal_action_delete m_signal_action_delete; type_signal_action_edit m_signal_action_edit; type_signal_channel_click m_signal_action_channel_click; type_signal_action_reaction_add m_signal_action_reaction_add; type_signal_action_reaction_remove m_signal_action_reaction_remove; - - type_signal_image_load m_signal_image_load; }; class ChatMessageHeader : public Gtk::ListBoxRow { diff --git a/components/chatwindow.cpp b/components/chatwindow.cpp index e2d5ac9..d4550e0 100644 --- a/components/chatwindow.cpp +++ b/components/chatwindow.cpp @@ -250,16 +250,6 @@ void ChatWindow::ProcessNewMessage(Snowflake id, bool prepend) { content->signal_action_reaction_remove().connect([this, id](const Glib::ustring ¶m) { m_signal_action_reaction_remove.emit(id, param); }); - content->signal_image_load().connect([this, id](std::string url) { - auto &mgr = Abaddon::Get().GetImageManager(); - mgr.LoadFromURL(url, [this, id, url](Glib::RefPtr<Gdk::Pixbuf> buf) { - if (m_id_to_widget.find(id) != m_id_to_widget.end()) { - auto *x = dynamic_cast<ChatMessageItemContainer *>(m_id_to_widget.at(id)); - if (x != nullptr) - x->UpdateImage(url, buf); - } - }); - }); content->signal_action_channel_click().connect([this](const Snowflake &id) { m_signal_action_channel_click.emit(id); }); diff --git a/components/lazyimage.cpp b/components/lazyimage.cpp new file mode 100644 index 0000000..08b9f10 --- /dev/null +++ b/components/lazyimage.cpp @@ -0,0 +1,41 @@ +#include "lazyimage.hpp" +#include "../abaddon.hpp" + +LazyImage::LazyImage(int w, int h, bool use_placeholder) + : m_width(w) + , m_height(h) { + static int sidx = 0; + sidx++; + m_idx = sidx; + if (use_placeholder) + property_pixbuf() = Abaddon::Get().GetImageManager().GetPlaceholder(w)->scale_simple(w, h, Gdk::INTERP_BILINEAR); + signal_draw().connect(sigc::mem_fun(*this, &LazyImage::OnDraw)); +} + +LazyImage::LazyImage(const std::string &url, int w, int h, bool use_placeholder) + : m_url(url) + , m_width(w) + , m_height(h) { + static int sidx = 0; + sidx++; + m_idx = sidx; + if (use_placeholder) + property_pixbuf() = Abaddon::Get().GetImageManager().GetPlaceholder(w)->scale_simple(w, h, Gdk::INTERP_BILINEAR); + signal_draw().connect(sigc::mem_fun(*this, &LazyImage::OnDraw)); +} + +void LazyImage::SetURL(const std::string &url) { + m_url = url; +} + +bool LazyImage::OnDraw(const Cairo::RefPtr<Cairo::Context> &context) { + if (!m_needs_request || m_url == "") return false; + m_needs_request = false; + + auto cb = [this](const Glib::RefPtr<Gdk::Pixbuf> &pb) { + property_pixbuf() = pb->scale_simple(m_width, m_height, Gdk::INTERP_BILINEAR); + }; + Abaddon::Get().GetImageManager().LoadFromURL(m_url, sigc::track_obj(cb, *this)); + + return false; +} diff --git a/components/lazyimage.hpp b/components/lazyimage.hpp new file mode 100644 index 0000000..54282b5 --- /dev/null +++ b/components/lazyimage.hpp @@ -0,0 +1,20 @@ +#pragma once +#include <gtkmm.h> + +// loads an image only when the widget is drawn for the first time +class LazyImage : public Gtk::Image { +public: + LazyImage(int w, int h, bool use_placeholder = true); + LazyImage(const std::string &url, int w, int h, bool use_placeholder = true); + + void SetURL(const std::string &url); + +private: + bool OnDraw(const Cairo::RefPtr<Cairo::Context> &context); + + bool m_needs_request = true; + int m_idx; + std::string m_url; + int m_width; + int m_height; +}; diff --git a/components/memberlist.cpp b/components/memberlist.cpp index 14fb1f4..81abb6c 100644 --- a/components/memberlist.cpp +++ b/components/memberlist.cpp @@ -7,7 +7,10 @@ MemberListUserRow::MemberListUserRow(Snowflake guild_id, const UserData *data) { m_ev = Gtk::manage(new Gtk::EventBox); m_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL)); m_label = Gtk::manage(new Gtk::Label); - m_avatar = Gtk::manage(new Gtk::Image(Abaddon::Get().GetImageManager().GetPlaceholder(16))); + m_avatar = Gtk::manage(new LazyImage(16, 16)); + + if (data->HasAvatar()) + m_avatar->SetURL(data->GetAvatarURL("png")); get_style_context()->add_class("members-row"); get_style_context()->add_class("members-row-member"); @@ -142,22 +145,6 @@ void MemberList::UpdateMemberListInternal() { auto add_user = [this, &user_to_color](const UserData *data) { auto *row = Gtk::manage(new MemberListUserRow(m_guild_id, data)); m_id_to_row[data->ID] = row; - - if (data->HasAvatar()) { - Snowflake id = data->ID; - Abaddon::Get().GetImageManager().LoadFromURL(data->GetAvatarURL("png", "16"), [this, id](Glib::RefPtr<Gdk::Pixbuf> pbuf) { - Glib::signal_idle().connect([this, id, pbuf]() -> bool { - if (m_id_to_row.find(id) != m_id_to_row.end()) { - auto *foundrow = static_cast<MemberListUserRow *>(m_id_to_row.at(id)); - if (foundrow != nullptr) - foundrow->SetAvatarFromPixbuf(pbuf); - } - - return false; - }); - }); - } - AttachUserMenuHandler(row, data->ID); m_listbox->add(*row); }; diff --git a/components/memberlist.hpp b/components/memberlist.hpp index a3642c9..f19880e 100644 --- a/components/memberlist.hpp +++ b/components/memberlist.hpp @@ -3,6 +3,7 @@ #include <mutex> #include <unordered_map> #include "../discord/discord.hpp" +#include "lazyimage.hpp" class MemberListUserRow : public Gtk::ListBoxRow { public: @@ -14,7 +15,7 @@ public: private: Gtk::EventBox *m_ev; Gtk::Box *m_box; - Gtk::Image *m_avatar; + LazyImage *m_avatar; Gtk::Label *m_label; }; |