summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorouwou <26526779+ouwou@users.noreply.github.com>2020-12-22 02:24:09 -0500
committerouwou <26526779+ouwou@users.noreply.github.com>2020-12-22 02:24:09 -0500
commit81d3ab2f86e79fc07895f8a288eb3366fc4bddcb (patch)
tree9a6ab59551562db8188be71b81cb40d8a17712da
parent8a2f13795ddb13f6a6bb6d67ea409a628fe1d03b (diff)
downloadabaddon-portaudio-81d3ab2f86e79fc07895f8a288eb3366fc4bddcb.tar.gz
abaddon-portaudio-81d3ab2f86e79fc07895f8a288eb3366fc4bddcb.zip
animated avatars on hover
-rw-r--r--components/chatmessage.cpp86
-rw-r--r--components/chatmessage.hpp12
-rw-r--r--discord/user.cpp4
-rw-r--r--discord/user.hpp1
4 files changed, 81 insertions, 22 deletions
diff --git a/components/chatmessage.cpp b/components/chatmessage.cpp
index f0df016..0e1e5bf 100644
--- a/components/chatmessage.cpp
+++ b/components/chatmessage.cpp
@@ -4,6 +4,7 @@
#include <unordered_map>
constexpr const int EmojiSize = 24; // settings eventually
+constexpr const int AvatarSize = 32;
ChatMessageItemContainer::ChatMessageItemContainer() {
m_main = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
@@ -44,14 +45,14 @@ ChatMessageItemContainer *ChatMessageItemContainer::FromMessage(Snowflake id) {
if (data->Content.size() > 0 || data->Type != MessageType::DEFAULT) {
container->m_text_component = container->CreateTextComponent(&*data);
- container->AttachGuildMenuHandler(container->m_text_component);
+ container->AttachEventHandlers(container->m_text_component);
container->m_main->add(*container->m_text_component);
}
// there should only ever be 1 embed (i think?)
if (data->Embeds.size() == 1) {
container->m_embed_component = container->CreateEmbedComponent(&*data);
- container->AttachGuildMenuHandler(container->m_embed_component);
+ container->AttachEventHandlers(container->m_embed_component);
container->m_main->add(*container->m_embed_component);
}
@@ -103,7 +104,7 @@ void ChatMessageItemContainer::UpdateContent() {
if (m_embed_imgurl.size() > 0) {
m_signal_image_load.emit(m_embed_imgurl);
}
- AttachGuildMenuHandler(m_embed_component);
+ AttachEventHandlers(m_embed_component);
m_main->add(*m_embed_component);
}
}
@@ -375,7 +376,7 @@ Gtk::Widget *ChatMessageItemContainer::CreateImageComponent(const AttachmentData
widget->set_halign(Gtk::ALIGN_START);
widget->set_size_request(w, h);
- AttachGuildMenuHandler(ev);
+ AttachEventHandlers(ev);
AddClickHandler(ev, data.URL);
HandleImage(data, widget, data.ProxyURL);
@@ -390,7 +391,7 @@ Gtk::Widget *ChatMessageItemContainer::CreateAttachmentComponent(const Attachmen
ev->get_style_context()->add_class("message-attachment-box");
ev->add(*btn);
- AttachGuildMenuHandler(ev);
+ AttachEventHandlers(ev);
AddClickHandler(ev, data.URL);
return ev;
@@ -410,7 +411,7 @@ Gtk::Widget *ChatMessageItemContainer::CreateStickerComponent(const Sticker &dat
// clang-format on
}
- AttachGuildMenuHandler(box);
+ AttachEventHandlers(box);
return box;
}
@@ -859,21 +860,40 @@ ChatMessageItemContainer::type_signal_action_reaction_remove ChatMessageItemCont
return m_signal_action_reaction_remove;
}
+ChatMessageItemContainer::type_signal_enter ChatMessageItemContainer::signal_enter() {
+ return m_signal_enter;
+}
+
+ChatMessageItemContainer::type_signal_leave ChatMessageItemContainer::signal_leave() {
+ return m_signal_leave;
+}
+
ChatMessageItemContainer::type_signal_image_load ChatMessageItemContainer::signal_image_load() {
return m_signal_image_load;
}
-void ChatMessageItemContainer::AttachGuildMenuHandler(Gtk::Widget *widget) {
- // clang-format off
- widget->signal_button_press_event().connect([this](GdkEventButton *event) -> bool {
+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) {
- ShowMenu(reinterpret_cast<GdkEvent*>(event));
+ ShowMenu(reinterpret_cast<GdkEvent *>(event));
return true;
}
return false;
- }, false);
- // clang-format on
+ };
+ widget->signal_button_press_event().connect(on_button_press_event, false);
+
+ widget->add_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
+ const auto on_notify_crossing = [this](GdkEventCrossing *event) -> bool {
+ if (event->type == GDK_ENTER_NOTIFY)
+ m_signal_enter.emit();
+ else if (event->type == GDK_LEAVE_NOTIFY)
+ m_signal_leave.emit();
+
+ return false;
+ };
+ widget->signal_enter_notify_event().connect(on_notify_crossing);
+ widget->signal_leave_notify_event().connect(on_notify_crossing);
}
ChatMessageHeader::ChatMessageHeader(const Message *data) {
@@ -890,16 +910,22 @@ ChatMessageHeader::ChatMessageHeader(const Message *data) {
const auto author = Abaddon::Get().GetDiscordClient().GetUser(UserID);
auto &img = Abaddon::Get().GetImageManager();
- Glib::RefPtr<Gdk::Pixbuf> buf;
- if (author.has_value())
- buf = img.GetFromURLIfCached(author->GetAvatarURL());
-
- if (buf)
- m_avatar = Gtk::manage(new Gtk::Image(buf));
- else {
- m_avatar = Gtk::manage(new Gtk::Image(img.GetPlaceholder(32)));
- if (author.has_value())
+
+ auto static_buf = img.GetFromURLIfCached(author->GetAvatarURL());
+ auto anim_buf = img.GetAnimationFromURLIfCached(author->GetAvatarURL("gif"), AvatarSize, AvatarSize);
+
+ if (anim_buf)
+ m_anim_avatar = anim_buf;
+
+ if (static_buf) {
+ m_static_avatar = static_buf;
+ m_avatar = Gtk::manage(new Gtk::Image(static_buf));
+ } else {
+ m_avatar = Gtk::manage(new Gtk::Image(img.GetPlaceholder(AvatarSize)));
+ if (author.has_value()) {
img.LoadFromURL(author->GetAvatarURL(), sigc::mem_fun(*this, &ChatMessageHeader::OnAvatarLoad));
+ img.LoadAnimationFromURL(author->GetAvatarURL("gif"), AvatarSize, AvatarSize, sigc::mem_fun(*this, &ChatMessageHeader::OnAnimatedAvatarLoad));
+ }
}
get_style_context()->add_class("message-container");
@@ -990,9 +1016,14 @@ void ChatMessageHeader::UpdateNameColor() {
}
void ChatMessageHeader::OnAvatarLoad(const Glib::RefPtr<Gdk::Pixbuf> &pixbuf) {
+ m_static_avatar = pixbuf;
m_avatar->property_pixbuf() = pixbuf;
}
+void ChatMessageHeader::OnAnimatedAvatarLoad(const Glib::RefPtr<Gdk::PixbufAnimation> &pixbuf) {
+ m_anim_avatar = pixbuf;
+}
+
void ChatMessageHeader::AttachUserMenuHandler(Gtk::Widget &widget) {
widget.signal_button_press_event().connect([this](GdkEventButton *ev) -> bool {
if (ev->type == GDK_BUTTON_PRESS && ev->button == GDK_BUTTON_SECONDARY) {
@@ -1022,6 +1053,19 @@ ChatMessageHeader::type_signal_action_open_user_menu ChatMessageHeader::signal_a
}
void ChatMessageHeader::AddContent(Gtk::Widget *widget, bool prepend) {
+ if (Abaddon::Get().GetSettings().GetShowAnimations()) {
+ auto *container = dynamic_cast<ChatMessageItemContainer *>(widget);
+ if (container != nullptr) {
+ container->signal_enter().connect([this] {
+ if (m_anim_avatar)
+ m_avatar->property_pixbuf_animation() = m_anim_avatar;
+ });
+ container->signal_leave().connect([this] {
+ if (m_anim_avatar) // if there is no anim avatar then it would have never switched off
+ m_avatar->property_pixbuf() = m_static_avatar;
+ });
+ }
+ }
m_content_box->add(*widget);
if (prepend)
m_content_box->reorder_child(*widget, 1);
diff --git a/components/chatmessage.hpp b/components/chatmessage.hpp
index cbc774b..7ba85bc 100644
--- a/components/chatmessage.hpp
+++ b/components/chatmessage.hpp
@@ -56,7 +56,7 @@ protected:
std::unordered_map<std::string, std::pair<Gtk::Image *, AttachmentData>> m_img_loadmap;
- void AttachGuildMenuHandler(Gtk::Widget *widget);
+ void AttachEventHandlers(Gtk::Widget *widget);
void ShowMenu(GdkEvent *event);
Gtk::Menu m_menu;
@@ -88,12 +88,16 @@ public:
typedef sigc::signal<void, Snowflake> type_signal_channel_click;
typedef sigc::signal<void, Glib::ustring> type_signal_action_reaction_add;
typedef sigc::signal<void, Glib::ustring> type_signal_action_reaction_remove;
+ typedef sigc::signal<void> type_signal_enter;
+ typedef sigc::signal<void> type_signal_leave;
type_signal_action_delete signal_action_delete();
type_signal_action_edit signal_action_edit();
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_enter signal_enter();
+ type_signal_leave signal_leave();
type_signal_image_load signal_image_load();
@@ -103,6 +107,8 @@ private:
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_enter m_signal_enter;
+ type_signal_leave m_signal_leave;
type_signal_image_load m_signal_image_load;
};
@@ -118,6 +124,7 @@ public:
protected:
void OnAvatarLoad(const Glib::RefPtr<Gdk::Pixbuf> &pixbuf);
+ void OnAnimatedAvatarLoad(const Glib::RefPtr<Gdk::PixbufAnimation> &pixbuf);
void AttachUserMenuHandler(Gtk::Widget &widget);
@@ -133,6 +140,9 @@ protected:
Gtk::Image *m_avatar;
Gtk::EventBox *m_avatar_ev;
+ Glib::RefPtr<Gdk::Pixbuf> m_static_avatar;
+ Glib::RefPtr<Gdk::PixbufAnimation> m_anim_avatar;
+
typedef sigc::signal<void> type_signal_action_insert_mention;
typedef sigc::signal<void, const GdkEvent *> type_signal_action_open_user_menu;
diff --git a/discord/user.cpp b/discord/user.cpp
index 01efe45..580f2ac 100644
--- a/discord/user.cpp
+++ b/discord/user.cpp
@@ -5,6 +5,10 @@ bool User::HasAvatar() const {
return Avatar.size() > 0;
}
+bool User::HasAnimatedAvatar() const {
+ return Avatar.size() > 0 && Avatar[0] == 'a' && Avatar[1] == '_';
+}
+
std::string User::GetAvatarURL(std::string ext, std::string size) const {
return "https://cdn.discordapp.com/avatars/" + std::to_string(ID) + "/" + Avatar + "." + ext + "?size=" + size;
}
diff --git a/discord/user.hpp b/discord/user.hpp
index 6480f57..2427b0b 100644
--- a/discord/user.hpp
+++ b/discord/user.hpp
@@ -29,6 +29,7 @@ struct User {
static void update_from_json(const nlohmann::json &j, User &m);
bool HasAvatar() const;
+ bool HasAnimatedAvatar() const;
std::string GetAvatarURL(std::string ext = "png", std::string size = "32") const;
Snowflake GetHoistedRole(Snowflake guild_id, bool with_color = false) const;
std::string GetMention() const;