summaryrefslogtreecommitdiff
path: root/windows
diff options
context:
space:
mode:
authorouwou <26526779+ouwou@users.noreply.github.com>2021-03-17 23:55:41 -0400
committerouwou <26526779+ouwou@users.noreply.github.com>2021-03-17 23:55:41 -0400
commit60404783bd4ce9be26233fe66fc3a74475d9eaa3 (patch)
tree7fd851858e9bdf25ad36c0e1542f5b28fb1c1e64 /windows
parent65943b4bd74ae52e6f6ffbff0e9ba619053172d6 (diff)
downloadabaddon-portaudio-60404783bd4ce9be26233fe66fc3a74475d9eaa3.tar.gz
abaddon-portaudio-60404783bd4ce9be26233fe66fc3a74475d9eaa3.zip
manage emojis
Diffstat (limited to 'windows')
-rw-r--r--windows/guildsettings/emojispane.cpp255
-rw-r--r--windows/guildsettings/emojispane.hpp55
-rw-r--r--windows/guildsettingswindow.cpp5
-rw-r--r--windows/guildsettingswindow.hpp2
4 files changed, 316 insertions, 1 deletions
diff --git a/windows/guildsettings/emojispane.cpp b/windows/guildsettings/emojispane.cpp
new file mode 100644
index 0000000..178b533
--- /dev/null
+++ b/windows/guildsettings/emojispane.cpp
@@ -0,0 +1,255 @@
+#include "emojispane.hpp"
+#include "../../abaddon.hpp"
+#include "../../components/cellrendererpixbufanimation.hpp"
+
+GuildSettingsEmojisPane::GuildSettingsEmojisPane(Snowflake guild_id)
+ : Gtk::Box(Gtk::ORIENTATION_VERTICAL)
+ , GuildID(guild_id)
+ , m_model(Gtk::ListStore::create(m_columns))
+ , m_filter(Gtk::TreeModelFilter::create(m_model))
+ , m_menu_copy_id("Copy ID")
+ , m_menu_delete("Delete")
+ , m_menu_copy_emoji_url("Copy Emoji URL")
+ , m_menu_show_emoji("Open in Browser") {
+ set_name("guild-emojis-pane");
+
+ m_view_scroll.set_hexpand(true);
+ m_view_scroll.set_vexpand(true);
+
+ m_view.signal_button_press_event().connect(sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnTreeButtonPress), false);
+
+ m_menu_copy_id.signal_activate().connect(sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnMenuCopyID));
+ m_menu_delete.signal_activate().connect(sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnMenuDelete));
+ m_menu_copy_emoji_url.signal_activate().connect(sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnMenuCopyEmojiURL));
+ m_menu_show_emoji.signal_activate().connect(sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnMenuShowEmoji));
+
+ m_menu.append(m_menu_delete);
+ m_menu.append(m_menu_copy_id);
+ m_menu.append(m_menu_copy_emoji_url);
+ m_menu.append(m_menu_show_emoji);
+ m_menu.show_all();
+
+ auto &discord = Abaddon::Get().GetDiscordClient();
+ auto &img = Abaddon::Get().GetImageManager();
+
+ discord.signal_guild_emojis_update().connect(sigc::hide<0>(sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnFetchEmojis)));
+
+ const auto self_id = discord.GetUserData().ID;
+ const bool can_manage = discord.HasGuildPermission(self_id, GuildID, Permission::MANAGE_EMOJIS);
+ m_menu_delete.set_sensitive(can_manage);
+
+ m_search.set_placeholder_text("Filter");
+ m_search.signal_changed().connect([this]() {
+ m_filter->refilter();
+ });
+
+ m_view_scroll.add(m_view);
+ add(m_search);
+ add(m_view_scroll);
+ m_search.show();
+ m_view.show();
+ m_view_scroll.show();
+
+ m_filter->set_visible_func([this](const Gtk::TreeModel::const_iterator &iter) -> bool {
+ const auto text = m_search.get_text();
+ if (text == "") return true;
+ return StringContainsCaseless((*iter)[m_columns.m_col_name], text);
+ });
+ m_view.set_enable_search(false);
+ m_view.set_model(m_filter);
+
+ auto *column = Gtk::manage(new Gtk::TreeView::Column("Emoji"));
+ auto *renderer = Gtk::manage(new CellRendererPixbufAnimation);
+ column->pack_start(*renderer);
+ column->add_attribute(renderer->property_pixbuf(), m_columns.m_col_pixbuf);
+ column->add_attribute(renderer->property_pixbuf_animation(), m_columns.m_col_pixbuf_animation);
+ m_view.append_column(*column);
+
+ if (can_manage) {
+ auto *column = Gtk::manage(new Gtk::TreeView::Column("Name"));
+ auto *renderer = Gtk::manage(new Gtk::CellRendererText);
+ column->pack_start(*renderer);
+ column->add_attribute(renderer->property_text(), m_columns.m_col_name);
+ renderer->property_editable() = true;
+ renderer->signal_edited().connect([this, renderer, column](const Glib::ustring &path, const Glib::ustring &text) {
+ std::string new_str;
+ int size = 0;
+ for (const auto ch : text) {
+ if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_')
+ new_str += ch;
+ else if (ch == ' ')
+ new_str += '_';
+ if (++size == 32) break;
+ }
+ if (auto row = *m_model->get_iter(path)) {
+ row[m_columns.m_col_name] = new_str;
+ OnEditName(row[m_columns.m_col_id], new_str);
+ }
+ });
+ m_view.append_column(*column);
+ } else
+ m_view.append_column("Name", m_columns.m_col_name);
+ if (can_manage)
+ m_view.append_column("Creator", m_columns.m_col_creator);
+ m_view.append_column("Is Animated?", m_columns.m_col_animated);
+
+ for (const auto column : m_view.get_columns())
+ column->set_resizable(true);
+}
+
+void GuildSettingsEmojisPane::on_switched_to() {
+ m_view.grab_focus();
+
+ if (m_requested) return;
+ m_requested = true;
+
+ auto &discord = Abaddon::Get().GetDiscordClient();
+ const auto self_id = discord.GetUserData().ID;
+ const bool can_manage = discord.HasGuildPermission(self_id, GuildID, Permission::MANAGE_EMOJIS);
+ m_menu_delete.set_sensitive(can_manage);
+
+ discord.FetchGuildEmojis(GuildID, sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnFetchEmojis));
+}
+
+void GuildSettingsEmojisPane::AddEmojiRow(const EmojiData &emoji) {
+ auto &img = Abaddon::Get().GetImageManager();
+
+ auto &row = *m_model->append();
+
+ row[m_columns.m_col_id] = emoji.ID;
+ row[m_columns.m_col_pixbuf] = img.GetPlaceholder(32);
+ row[m_columns.m_col_name] = emoji.Name;
+ if (emoji.Creator.has_value())
+ row[m_columns.m_col_creator] = emoji.Creator->Username + "#" + emoji.Creator->Discriminator;
+ if (emoji.IsAnimated.has_value())
+ row[m_columns.m_col_animated] = *emoji.IsAnimated ? "Yes" : "No";
+ else
+ row[m_columns.m_col_animated] = "No";
+ if (emoji.IsAvailable.has_value())
+ row[m_columns.m_col_available] = *emoji.IsAvailable ? "Yes" : "No";
+ else
+ row[m_columns.m_col_available] = "Yes";
+
+ static bool show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
+ if (show_animations && emoji.IsAnimated.has_value() && *emoji.IsAnimated) {
+ const auto cb = [this, id = emoji.ID](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
+ for (auto &row : m_model->children()) {
+ if (static_cast<Snowflake>(row[m_columns.m_col_id]) == id) {
+ row[m_columns.m_col_pixbuf_animation] = pb;
+ return;
+ }
+ }
+ };
+ img.LoadAnimationFromURL(emoji.GetURL("gif"), 32, 32, sigc::track_obj(cb, *this));
+ } else {
+ const auto cb = [this, id = emoji.ID](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
+ for (auto &row : m_model->children()) {
+ if (static_cast<Snowflake>(row[m_columns.m_col_id]) == id) {
+ row[m_columns.m_col_pixbuf] = pb->scale_simple(32, 32, Gdk::INTERP_BILINEAR);
+ return;
+ }
+ }
+ };
+ img.LoadFromURL(emoji.GetURL(), sigc::track_obj(cb, *this));
+ }
+}
+
+void GuildSettingsEmojisPane::OnFetchEmojis(std::vector<EmojiData> emojis) {
+ m_model->clear();
+
+ // put animated emojis at the end then sort alphabetically
+ std::sort(emojis.begin(), emojis.end(), [&](const EmojiData &a, const EmojiData &b) {
+ const bool a_is_animated = a.IsAnimated.has_value() && *a.IsAnimated;
+ const bool b_is_animated = b.IsAnimated.has_value() && *b.IsAnimated;
+ if (a_is_animated == b_is_animated)
+ return a.Name < b.Name;
+ else if (a_is_animated && !b_is_animated)
+ return false;
+ else if (!a_is_animated && b_is_animated)
+ return true;
+ return false; // this wont happen please be quiet compiler
+ });
+
+ for (const auto &emoji : emojis)
+ AddEmojiRow(emoji);
+}
+
+void GuildSettingsEmojisPane::OnEditName(Snowflake id, const std::string &name) {
+ const auto cb = [this](bool success) {
+ if (!success) {
+ Gtk::MessageDialog dlg("Failed to set emoji name", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
+ dlg.run();
+ }
+ };
+ Abaddon::Get().GetDiscordClient().ModifyEmojiName(GuildID, id, name, cb);
+}
+
+void GuildSettingsEmojisPane::OnMenuCopyID() {
+ if (auto selected_row = *m_view.get_selection()->get_selected()) {
+ const auto id = static_cast<Snowflake>(selected_row[m_columns.m_col_id]);
+ Gtk::Clipboard::get()->set_text(std::to_string(id));
+ }
+}
+
+void GuildSettingsEmojisPane::OnMenuDelete() {
+ if (auto selected_row = *m_view.get_selection()->get_selected()) {
+ const auto name = static_cast<Glib::ustring>(selected_row[m_columns.m_col_name]);
+ const auto id = static_cast<Snowflake>(selected_row[m_columns.m_col_id]);
+ if (auto *window = dynamic_cast<Gtk::Window *>(get_toplevel()))
+ if (Abaddon::Get().ShowConfirm("Are you sure you want to delete " + name + "?", window)) {
+ const auto cb = [this](bool success) {
+ if (!success) {
+ Gtk::MessageDialog dlg("Failed to delete emoji", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
+ dlg.run();
+ }
+ };
+ Abaddon::Get().GetDiscordClient().DeleteEmoji(GuildID, id, cb);
+ }
+ }
+}
+
+void GuildSettingsEmojisPane::OnMenuCopyEmojiURL() {
+ if (auto selected_row = *m_view.get_selection()->get_selected()) {
+ const auto id = static_cast<Snowflake>(selected_row[m_columns.m_col_id]);
+ const bool is_animated = static_cast<Glib::ustring>(selected_row[m_columns.m_col_animated]) == "Yes";
+ Gtk::Clipboard::get()->set_text(EmojiData::URLFromID(id, is_animated ? "gif" : "png", "256"));
+ }
+}
+
+void GuildSettingsEmojisPane::OnMenuShowEmoji() {
+ if (auto selected_row = *m_view.get_selection()->get_selected()) {
+ const auto id = static_cast<Snowflake>(selected_row[m_columns.m_col_id]);
+ const bool is_animated = static_cast<Glib::ustring>(selected_row[m_columns.m_col_animated]) == "Yes";
+ LaunchBrowser(EmojiData::URLFromID(id, is_animated ? "gif" : "png", "256"));
+ }
+}
+
+bool GuildSettingsEmojisPane::OnTreeButtonPress(GdkEventButton *event) {
+ if (event->button == GDK_BUTTON_SECONDARY) {
+ auto &discord = Abaddon::Get().GetDiscordClient();
+ const auto self_id = discord.GetUserData().ID;
+ const bool can_manage = discord.HasGuildPermission(self_id, GuildID, Permission::MANAGE_EMOJIS);
+ m_menu_delete.set_sensitive(can_manage);
+
+ auto selection = m_view.get_selection();
+ Gtk::TreeModel::Path path;
+ if (m_view.get_path_at_pos(event->x, event->y, path)) {
+ m_view.get_selection()->select(path);
+ m_menu.popup_at_pointer(reinterpret_cast<GdkEvent *>(event));
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+GuildSettingsEmojisPane::ModelColumns::ModelColumns() {
+ add(m_col_id);
+ add(m_col_pixbuf);
+ add(m_col_pixbuf_animation);
+ add(m_col_name);
+ add(m_col_creator);
+ add(m_col_animated);
+ add(m_col_available);
+}
diff --git a/windows/guildsettings/emojispane.hpp b/windows/guildsettings/emojispane.hpp
new file mode 100644
index 0000000..806babb
--- /dev/null
+++ b/windows/guildsettings/emojispane.hpp
@@ -0,0 +1,55 @@
+#pragma once
+#include <gtkmm.h>
+#include "../../components/inotifyswitched.hpp"
+#include "../../discord/emoji.hpp"
+
+class GuildSettingsEmojisPane : public Gtk::Box
+ , public INotifySwitched {
+public:
+ GuildSettingsEmojisPane(Snowflake guild_id);
+
+private:
+ void on_switched_to() override;
+
+ bool m_requested = false;
+
+ void AddEmojiRow(const EmojiData &emoji);
+
+ void OnFetchEmojis(std::vector<EmojiData> emojis);
+
+ void OnEditName(Snowflake id, const std::string &name);
+ void OnMenuCopyID();
+ void OnMenuDelete();
+ void OnMenuCopyEmojiURL();
+ void OnMenuShowEmoji();
+ bool OnTreeButtonPress(GdkEventButton *event);
+
+ Snowflake GuildID;
+
+ Gtk::Entry m_search;
+ Gtk::ScrolledWindow m_view_scroll;
+ Gtk::TreeView m_view;
+
+ class ModelColumns : public Gtk::TreeModel::ColumnRecord {
+ public:
+ ModelColumns();
+
+ Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf>> m_col_pixbuf;
+ Gtk::TreeModelColumn<Glib::RefPtr<Gdk::PixbufAnimation>> m_col_pixbuf_animation;
+ Gtk::TreeModelColumn<Glib::ustring> m_col_name;
+ Gtk::TreeModelColumn<Glib::ustring> m_col_creator;
+ Gtk::TreeModelColumn<Glib::ustring> m_col_animated;
+ Gtk::TreeModelColumn<Glib::ustring> m_col_available;
+ Gtk::TreeModelColumn<Snowflake> m_col_id;
+ };
+
+ ModelColumns m_columns;
+ Glib::RefPtr<Gtk::ListStore> m_model;
+ Glib::RefPtr<Gtk::TreeModelFilter> m_filter;
+
+ Gtk::Menu m_menu;
+ Gtk::MenuItem m_menu_delete;
+ Gtk::MenuItem m_menu_copy_id;
+ Gtk::MenuItem m_menu_copy_emoji_url;
+ Gtk::MenuItem m_menu_show_emoji;
+};
diff --git a/windows/guildsettingswindow.cpp b/windows/guildsettingswindow.cpp
index bcbc393..e3b66f7 100644
--- a/windows/guildsettingswindow.cpp
+++ b/windows/guildsettingswindow.cpp
@@ -10,7 +10,8 @@ GuildSettingsWindow::GuildSettingsWindow(Snowflake id)
, m_pane_invites(id)
, m_pane_audit_log(id)
, m_pane_members(id)
- , m_pane_roles(id) {
+ , m_pane_roles(id)
+ , m_pane_emojis(id) {
auto &discord = Abaddon::Get().GetDiscordClient();
const auto guild = *discord.GetGuild(id);
@@ -51,6 +52,7 @@ GuildSettingsWindow::GuildSettingsWindow(Snowflake id)
m_pane_roles.show();
m_pane_bans.show();
m_pane_invites.show();
+ m_pane_emojis.show();
m_pane_audit_log.show();
m_stack.set_transition_duration(100);
@@ -68,6 +70,7 @@ GuildSettingsWindow::GuildSettingsWindow(Snowflake id)
m_stack.add(m_pane_bans, "bans", "Bans");
if (discord.HasGuildPermission(self_id, GuildID, Permission::MANAGE_GUILD))
m_stack.add(m_pane_invites, "invites", "Invites");
+ m_stack.add(m_pane_emojis, "emojis", "Emojis");
if (discord.HasGuildPermission(self_id, GuildID, Permission::VIEW_AUDIT_LOG))
m_stack.add(m_pane_audit_log, "audit-log", "Audit Log");
m_stack.show();
diff --git a/windows/guildsettingswindow.hpp b/windows/guildsettingswindow.hpp
index 3d9d857..7447840 100644
--- a/windows/guildsettingswindow.hpp
+++ b/windows/guildsettingswindow.hpp
@@ -7,6 +7,7 @@
#include "guildsettings/auditlogpane.hpp"
#include "guildsettings/memberspane.hpp"
#include "guildsettings/rolespane.hpp"
+#include "guildsettings/emojispane.hpp"
class GuildSettingsWindow : public Gtk::Window {
public:
@@ -22,6 +23,7 @@ private:
GuildSettingsRolesPane m_pane_roles;
GuildSettingsBansPane m_pane_bans;
GuildSettingsInvitesPane m_pane_invites;
+ GuildSettingsEmojisPane m_pane_emojis;
GuildSettingsAuditLogPane m_pane_audit_log;
Snowflake GuildID;