animated emojis

This commit is contained in:
ouwou
2020-12-22 01:23:56 -05:00
parent d8ff05ddf8
commit 8a2f13795d
3 changed files with 62 additions and 27 deletions

View File

@@ -3,6 +3,8 @@
#include "../util.hpp" #include "../util.hpp"
#include <unordered_map> #include <unordered_map>
constexpr const int EmojiSize = 24; // settings eventually
ChatMessageItemContainer::ChatMessageItemContainer() { ChatMessageItemContainer::ChatMessageItemContainer() {
m_main = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); m_main = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
add(*m_main); add(*m_main);
@@ -568,7 +570,7 @@ void ChatMessageItemContainer::HandleUserMentions(Gtk::TextView *tv) {
} }
void ChatMessageItemContainer::HandleStockEmojis(Gtk::TextView *tv) { void ChatMessageItemContainer::HandleStockEmojis(Gtk::TextView *tv) {
Abaddon::Get().GetEmojis().ReplaceEmojis(tv->get_buffer()); Abaddon::Get().GetEmojis().ReplaceEmojis(tv->get_buffer(), EmojiSize);
} }
void ChatMessageItemContainer::HandleCustomEmojis(Gtk::TextView *tv) { void ChatMessageItemContainer::HandleCustomEmojis(Gtk::TextView *tv) {
@@ -584,6 +586,8 @@ void ChatMessageItemContainer::HandleCustomEmojis(Gtk::TextView *tv) {
while (rgx->match(text, startpos, match)) { while (rgx->match(text, startpos, match)) {
int mstart, mend; int mstart, mend;
if (!match.fetch_pos(0, mstart, mend)) break; if (!match.fetch_pos(0, mstart, mend)) break;
const bool is_animated = match.fetch(0)[1] == 'a';
const bool show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
const auto chars_start = g_utf8_pointer_to_offset(text.c_str(), text.c_str() + mstart); const auto chars_start = g_utf8_pointer_to_offset(text.c_str(), text.c_str() + mstart);
const auto chars_end = g_utf8_pointer_to_offset(text.c_str(), text.c_str() + mend); const auto chars_end = g_utf8_pointer_to_offset(text.c_str(), text.c_str() + mend);
@@ -591,30 +595,61 @@ void ChatMessageItemContainer::HandleCustomEmojis(Gtk::TextView *tv) {
auto end_it = buf->get_iter_at_offset(chars_end); auto end_it = buf->get_iter_at_offset(chars_end);
startpos = mend; startpos = mend;
auto pixbuf = img.GetFromURLIfCached(Emoji::URLFromID(match.fetch(2))); if (is_animated && show_animations) {
if (pixbuf) { auto pixbuf = img.GetAnimationFromURLIfCached(Emoji::URLFromID(match.fetch(2), "gif"), EmojiSize, EmojiSize);
auto it = buf->erase(start_it, end_it); if (pixbuf) {
int alen = text.size(); const auto it = buf->erase(start_it, end_it);
text = GetText(buf); const int alen = text.size();
int blen = text.size(); text = GetText(buf);
startpos -= (alen - blen); const int blen = text.size();
buf->insert_pixbuf(it, pixbuf->scale_simple(24, 24, Gdk::INTERP_BILINEAR)); startpos -= (alen - blen);
const auto anchor = buf->create_child_anchor(it);
auto img = Gtk::manage(new Gtk::Image(pixbuf));
img->show();
tv->add_child_at_anchor(*img, anchor);
} else {
const auto mark_start = buf->create_mark(start_it, false);
end_it.backward_char();
const auto mark_end = buf->create_mark(end_it, false);
const auto cb = [this, tv, buf, mark_start, mark_end](const Glib::RefPtr<Gdk::PixbufAnimation> &pixbuf) {
auto start_it = mark_start->get_iter();
auto end_it = mark_end->get_iter();
end_it.forward_char();
buf->delete_mark(mark_start);
buf->delete_mark(mark_end);
auto it = buf->erase(start_it, end_it);
const auto anchor = buf->create_child_anchor(it);
auto img = Gtk::manage(new Gtk::Image(pixbuf));
img->show();
tv->add_child_at_anchor(*img, anchor);
};
img.LoadAnimationFromURL(Emoji::URLFromID(match.fetch(2), "gif"), EmojiSize, EmojiSize, sigc::track_obj(cb, tv));
}
} else { } else {
// clang-format off auto pixbuf = img.GetFromURLIfCached(Emoji::URLFromID(match.fetch(2)));
// can't erase before pixbuf is ready or else marks that are in the same pos get mixed up if (pixbuf) {
auto mark_start = buf->create_mark(start_it, false); const auto it = buf->erase(start_it, end_it);
end_it.backward_char(); const int alen = text.size();
auto mark_end = buf->create_mark(end_it, false); text = GetText(buf);
img.LoadFromURL(Emoji::URLFromID(match.fetch(2)), sigc::track_obj([this, buf, mark_start, mark_end](Glib::RefPtr<Gdk::Pixbuf> pixbuf) { const int blen = text.size();
auto start_it = mark_start->get_iter(); startpos -= (alen - blen);
auto end_it = mark_end->get_iter(); buf->insert_pixbuf(it, pixbuf->scale_simple(EmojiSize, EmojiSize, Gdk::INTERP_BILINEAR));
end_it.forward_char(); } else {
buf->delete_mark(mark_start); // can't erase before pixbuf is ready or else marks that are in the same pos get mixed up
buf->delete_mark(mark_end); const auto mark_start = buf->create_mark(start_it, false);
auto it = buf->erase(start_it, end_it); end_it.backward_char();
buf->insert_pixbuf(it, pixbuf->scale_simple(24, 24, Gdk::INTERP_BILINEAR)); const auto mark_end = buf->create_mark(end_it, false);
}, tv)); const auto cb = [this, buf, mark_start, mark_end](const Glib::RefPtr<Gdk::Pixbuf> &pixbuf) {
// clang-format on auto start_it = mark_start->get_iter();
auto end_it = mark_end->get_iter();
end_it.forward_char();
buf->delete_mark(mark_start);
buf->delete_mark(mark_end);
auto it = buf->erase(start_it, end_it);
buf->insert_pixbuf(it, pixbuf->scale_simple(EmojiSize, EmojiSize, Gdk::INTERP_BILINEAR));
};
img.LoadFromURL(Emoji::URLFromID(match.fetch(2)), sigc::track_obj(cb, tv));
}
} }
text = GetText(buf); text = GetText(buf);

View File

@@ -32,6 +32,6 @@ std::string Emoji::GetURL() const {
return "https://cdn.discordapp.com/emojis/" + std::to_string(ID) + ".png"; return "https://cdn.discordapp.com/emojis/" + std::to_string(ID) + ".png";
} }
std::string Emoji::URLFromID(std::string emoji_id) { std::string Emoji::URLFromID(std::string emoji_id, std::string ext) {
return "https://cdn.discordapp.com/emojis/" + emoji_id + ".png"; return "https://cdn.discordapp.com/emojis/" + emoji_id + "." + ext;
} }

View File

@@ -19,5 +19,5 @@ struct Emoji {
friend void to_json(nlohmann::json &j, const Emoji &m); friend void to_json(nlohmann::json &j, const Emoji &m);
std::string GetURL() const; std::string GetURL() const;
static std::string URLFromID(std::string emoji_id); static std::string URLFromID(std::string emoji_id, std::string ext = "png");
}; };