forked from OpenGamers/abaddon
parent
f51ab48009
commit
462f801af2
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -43,6 +43,8 @@ jobs:
|
||||
del /f /s /q "${{ runner.workspace }}\build\CMakeCache.txt"
|
||||
xcopy /E /I "${{ github.workspace }}\css" "${{ runner.workspace }}\build\css"
|
||||
xcopy /E /I "${{ github.workspace }}\res" "${{ runner.workspace }}\build\res"
|
||||
mkdir "${{ runner.workspace }}\build\share"
|
||||
xcopy /E /I "${{ github.workspace }}\ci\gtk-for-windows\gtk-nsis-pack\share\glib-2.0" "${{ runner.workspace }}\build\share\glib-2.0"
|
||||
copy "${{ github.workspace }}\ci\vcpkg\installed\x64-windows\tools\glib\gspawn-win64-helper.exe" "${{ runner.workspace }}\build\gspawn-win64-helper.exe"
|
||||
copy "${{ github.workspace }}\ci\vcpkg\installed\x64-windows\tools\glib\gspawn-win64-helper-console.exe" "${{ runner.workspace }}\build\gspawn-win64-helper-console.exe"
|
||||
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -10,3 +10,6 @@
|
||||
[submodule "ci/vcpkg"]
|
||||
path = ci/vcpkg
|
||||
url = https://github.com/microsoft/vcpkg
|
||||
[submodule "ci/gtk-for-windows"]
|
||||
path = ci/gtk-for-windows
|
||||
url = https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer
|
||||
|
@ -43,6 +43,8 @@ file(GLOB ABADDON_SOURCES
|
||||
"components/*.cpp"
|
||||
"windows/*.hpp"
|
||||
"windows/*.cpp"
|
||||
"windows/guildsettings/*.hpp"
|
||||
"windows/guildsettings/*.cpp"
|
||||
"dialogs/*.hpp"
|
||||
"dialogs/*.cpp"
|
||||
)
|
||||
|
11
abaddon.cpp
11
abaddon.cpp
@ -9,6 +9,7 @@
|
||||
#include "dialogs/confirm.hpp"
|
||||
#include "dialogs/setstatus.hpp"
|
||||
#include "abaddon.hpp"
|
||||
#include "windows/guildsettingswindow.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma comment(lib, "crypt32.lib")
|
||||
@ -105,6 +106,7 @@ int Abaddon::StartGTK() {
|
||||
|
||||
m_main_window->GetChannelList()->signal_action_channel_item_select().connect(sigc::mem_fun(*this, &Abaddon::ActionChannelOpened));
|
||||
m_main_window->GetChannelList()->signal_action_guild_leave().connect(sigc::mem_fun(*this, &Abaddon::ActionLeaveGuild));
|
||||
m_main_window->GetChannelList()->signal_action_guild_settings().connect(sigc::mem_fun(*this, &Abaddon::ActionGuildSettings));
|
||||
|
||||
m_main_window->GetChatWindow()->signal_action_message_delete().connect(sigc::mem_fun(*this, &Abaddon::ActionChatDeleteMessage));
|
||||
m_main_window->GetChatWindow()->signal_action_message_edit().connect(sigc::mem_fun(*this, &Abaddon::ActionChatEditMessage));
|
||||
@ -231,6 +233,10 @@ const SettingsManager &Abaddon::GetSettings() const {
|
||||
return m_settings;
|
||||
}
|
||||
|
||||
Glib::RefPtr<Gtk::CssProvider> Abaddon::GetStyleProvider() {
|
||||
return m_css_provider;
|
||||
}
|
||||
|
||||
void Abaddon::ShowUserMenu(const GdkEvent *event, Snowflake id, Snowflake guild_id) {
|
||||
m_shown_user_menu_id = id;
|
||||
m_shown_user_menu_guild_id = guild_id;
|
||||
@ -455,6 +461,11 @@ void Abaddon::ActionReactionRemove(Snowflake id, const Glib::ustring ¶m) {
|
||||
m_discord.RemoveReaction(id, param);
|
||||
}
|
||||
|
||||
void Abaddon::ActionGuildSettings(Snowflake id) {
|
||||
auto *window = new GuildSettingsWindow(id);
|
||||
window->show();
|
||||
}
|
||||
|
||||
void Abaddon::ActionReloadSettings() {
|
||||
m_settings.Reload();
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ public:
|
||||
void ActionSetStatus();
|
||||
void ActionReactionAdd(Snowflake id, const Glib::ustring ¶m);
|
||||
void ActionReactionRemove(Snowflake id, const Glib::ustring ¶m);
|
||||
void ActionGuildSettings(Snowflake id);
|
||||
|
||||
void ActionReloadSettings();
|
||||
void ActionReloadCSS();
|
||||
@ -73,6 +74,8 @@ public:
|
||||
|
||||
const SettingsManager &GetSettings() const;
|
||||
|
||||
Glib::RefPtr<Gtk::CssProvider> GetStyleProvider();
|
||||
|
||||
protected:
|
||||
Snowflake m_shown_user_menu_id;
|
||||
Snowflake m_shown_user_menu_guild_id;
|
||||
|
1
ci/gtk-for-windows
Submodule
1
ci/gtk-for-windows
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 27bc126a0d9f1a3ac46c6cd7ce2e6b9eea813127
|
@ -117,6 +117,12 @@ ChannelListRowGuild::ChannelListRowGuild(const GuildData *data) {
|
||||
});
|
||||
m_menu.append(*m_menu_leave);
|
||||
|
||||
m_menu_settings = Gtk::manage(new Gtk::MenuItem("Guild _Settings", true));
|
||||
m_menu_settings->signal_activate().connect([this]() {
|
||||
m_signal_settings.emit();
|
||||
});
|
||||
m_menu.append(*m_menu_settings);
|
||||
|
||||
m_menu.show_all();
|
||||
|
||||
const auto show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
|
||||
@ -176,6 +182,10 @@ ChannelListRowGuild::type_signal_leave ChannelListRowGuild::signal_leave() {
|
||||
return m_signal_leave;
|
||||
}
|
||||
|
||||
ChannelListRowGuild::type_signal_settings ChannelListRowGuild::signal_settings() {
|
||||
return m_signal_settings;
|
||||
}
|
||||
|
||||
ChannelListRowCategory::ChannelListRowCategory(const ChannelData *data) {
|
||||
ID = data->ID;
|
||||
m_ev = Gtk::manage(new Gtk::EventBox);
|
||||
@ -519,6 +529,7 @@ void ChannelList::UpdateGuild(Snowflake id) {
|
||||
m_guild_id_to_row[new_row->ID] = new_row;
|
||||
new_row->signal_leave().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnGuildMenuLeave), new_row->ID));
|
||||
new_row->signal_copy_id().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnMenuCopyID), new_row->ID));
|
||||
new_row->signal_settings().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnGuildMenuSettings), new_row->ID));
|
||||
new_row->Children = children;
|
||||
for (auto child : children)
|
||||
child->Parent = new_row;
|
||||
@ -615,6 +626,7 @@ void ChannelList::InsertGuildAt(Snowflake id, int pos) {
|
||||
m_guild_id_to_row[guild_row->ID] = guild_row;
|
||||
guild_row->signal_leave().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnGuildMenuLeave), guild_row->ID));
|
||||
guild_row->signal_copy_id().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnMenuCopyID), guild_row->ID));
|
||||
guild_row->signal_settings().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnGuildMenuSettings), guild_row->ID));
|
||||
|
||||
// add channels with no parent category
|
||||
for (const auto &[pos, channel] : orphan_channels) {
|
||||
@ -726,6 +738,10 @@ void ChannelList::OnGuildMenuLeave(Snowflake id) {
|
||||
m_signal_action_guild_leave.emit(id);
|
||||
}
|
||||
|
||||
void ChannelList::OnGuildMenuSettings(Snowflake id) {
|
||||
m_signal_action_guild_settings.emit(id);
|
||||
}
|
||||
|
||||
void ChannelList::CheckBumpDM(Snowflake channel_id) {
|
||||
auto it = m_dm_id_to_row.find(channel_id);
|
||||
if (it == m_dm_id_to_row.end()) return;
|
||||
@ -756,3 +772,7 @@ ChannelList::type_signal_action_channel_item_select ChannelList::signal_action_c
|
||||
ChannelList::type_signal_action_guild_leave ChannelList::signal_action_guild_leave() {
|
||||
return m_signal_action_guild_leave;
|
||||
}
|
||||
|
||||
ChannelList::type_signal_action_guild_settings ChannelList::signal_action_guild_settings() {
|
||||
return m_signal_action_guild_settings;
|
||||
}
|
||||
|
@ -64,17 +64,21 @@ protected:
|
||||
Gtk::Menu m_menu;
|
||||
Gtk::MenuItem *m_menu_copyid;
|
||||
Gtk::MenuItem *m_menu_leave;
|
||||
Gtk::MenuItem *m_menu_settings;
|
||||
|
||||
private:
|
||||
typedef sigc::signal<void> type_signal_copy_id;
|
||||
typedef sigc::signal<void> type_signal_leave;
|
||||
typedef sigc::signal<void> type_signal_settings;
|
||||
|
||||
type_signal_copy_id m_signal_copy_id;
|
||||
type_signal_leave m_signal_leave;
|
||||
type_signal_settings m_signal_settings;
|
||||
|
||||
public:
|
||||
type_signal_copy_id signal_copy_id();
|
||||
type_signal_leave signal_leave();
|
||||
type_signal_settings signal_settings();
|
||||
};
|
||||
|
||||
class ChannelListRowCategory : public ChannelListRow {
|
||||
@ -156,6 +160,7 @@ protected:
|
||||
int m_guild_count;
|
||||
void OnMenuCopyID(Snowflake id);
|
||||
void OnGuildMenuLeave(Snowflake id);
|
||||
void OnGuildMenuSettings(Snowflake id);
|
||||
|
||||
Gtk::Menu m_channel_menu;
|
||||
Gtk::MenuItem *m_channel_menu_copyid;
|
||||
@ -179,11 +184,14 @@ protected:
|
||||
public:
|
||||
typedef sigc::signal<void, Snowflake> type_signal_action_channel_item_select;
|
||||
typedef sigc::signal<void, Snowflake> type_signal_action_guild_leave;
|
||||
typedef sigc::signal<void, Snowflake> type_signal_action_guild_settings;
|
||||
|
||||
type_signal_action_channel_item_select signal_action_channel_item_select();
|
||||
type_signal_action_guild_leave signal_action_guild_leave();
|
||||
type_signal_action_guild_settings signal_action_guild_settings();
|
||||
|
||||
protected:
|
||||
type_signal_action_channel_item_select m_signal_action_channel_item_select;
|
||||
type_signal_action_guild_leave m_signal_action_guild_leave;
|
||||
type_signal_action_guild_settings m_signal_action_guild_settings;
|
||||
};
|
||||
|
30
css/main.css
30
css/main.css
@ -162,16 +162,40 @@
|
||||
color: @text_color;
|
||||
}
|
||||
|
||||
paned separator {
|
||||
.app-window label:not(:disabled) {
|
||||
color: @text_color;
|
||||
}
|
||||
|
||||
.app-window entry {
|
||||
background: @secondary_color;
|
||||
color: @text_color;
|
||||
border: 1px solid #1c2e40;
|
||||
}
|
||||
|
||||
.app-window button {
|
||||
background: @secondary_color;
|
||||
color: @text_color;
|
||||
border: 1px solid #1c2e40;
|
||||
}
|
||||
|
||||
.app-window.background {
|
||||
background: @background_color;
|
||||
}
|
||||
|
||||
.app-window listbox {
|
||||
background: @background_color;
|
||||
}
|
||||
|
||||
.app-window paned separator {
|
||||
background: #37474f;
|
||||
}
|
||||
|
||||
scrollbar {
|
||||
.app-window scrollbar {
|
||||
background: @background_color;
|
||||
border-left: 1px solid transparent;
|
||||
}
|
||||
|
||||
menubar, menu {
|
||||
.app-window menubar, menu {
|
||||
background: @background_color;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ ConfirmDialog::ConfirmDialog(Gtk::Window &parent)
|
||||
, m_ok("OK")
|
||||
, m_cancel("Cancel") {
|
||||
set_default_size(300, 50);
|
||||
get_style_context()->add_class("app-window");
|
||||
|
||||
m_label.set_text("Are you sure?");
|
||||
|
||||
|
@ -7,6 +7,7 @@ EditMessageDialog::EditMessageDialog(Gtk::Window &parent)
|
||||
, m_ok("OK")
|
||||
, m_cancel("Cancel") {
|
||||
set_default_size(300, 50);
|
||||
get_style_context()->add_class("app-window");
|
||||
|
||||
m_ok.signal_clicked().connect([&]() {
|
||||
m_content = m_text.get_buffer()->get_text();
|
||||
|
@ -10,6 +10,7 @@ JoinGuildDialog::JoinGuildDialog(Gtk::Window &parent)
|
||||
, m_cancel("Cancel")
|
||||
, m_info("Enter code") {
|
||||
set_default_size(300, 50);
|
||||
get_style_context()->add_class("app-window");
|
||||
|
||||
Glib::signal_idle().connect(sigc::mem_fun(*this, &JoinGuildDialog::on_idle_slot));
|
||||
|
||||
|
@ -8,6 +8,7 @@ SetStatusDialog::SetStatusDialog(Gtk::Window &parent)
|
||||
, m_ok("OK")
|
||||
, m_cancel("Cancel") {
|
||||
set_default_size(300, 50);
|
||||
get_style_context()->add_class("app-window");
|
||||
|
||||
m_text.set_placeholder_text("Status text");
|
||||
|
||||
|
@ -7,6 +7,7 @@ TokenDialog::TokenDialog(Gtk::Window &parent)
|
||||
, m_ok("OK")
|
||||
, m_cancel("Cancel") {
|
||||
set_default_size(300, 50);
|
||||
get_style_context()->add_class("app-window");
|
||||
|
||||
m_ok.signal_clicked().connect([&]() {
|
||||
m_token = m_entry.get_text();
|
||||
|
@ -437,6 +437,36 @@ void DiscordClient::RemoveReaction(Snowflake id, Glib::ustring param) {
|
||||
m_http.MakeDELETE("/channels/" + std::to_string(channel_id) + "/messages/" + std::to_string(id) + "/reactions/" + param + "/@me", [](auto) {});
|
||||
}
|
||||
|
||||
void DiscordClient::SetGuildName(Snowflake id, const Glib::ustring &name) {
|
||||
SetGuildName(id, name, [](auto) {});
|
||||
}
|
||||
|
||||
void DiscordClient::SetGuildName(Snowflake id, const Glib::ustring &name, sigc::slot<void(bool success)> callback) {
|
||||
ModifyGuildObject obj;
|
||||
obj.Name = name;
|
||||
sigc::signal<void, bool> signal;
|
||||
signal.connect(callback);
|
||||
m_http.MakePATCH("/guilds/" + std::to_string(id), nlohmann::json(obj).dump(), [this, signal](const cpr::Response &r) {
|
||||
const auto success = r.status_code == 200;
|
||||
signal.emit(success);
|
||||
});
|
||||
}
|
||||
|
||||
void DiscordClient::SetGuildIcon(Snowflake id, const std::string &data) {
|
||||
SetGuildIcon(id, data, [](auto) {});
|
||||
}
|
||||
|
||||
void DiscordClient::SetGuildIcon(Snowflake id, const std::string &data, sigc::slot<void(bool success)> callback) {
|
||||
ModifyGuildObject obj;
|
||||
obj.IconData = data;
|
||||
sigc::signal<void, bool> signal;
|
||||
signal.connect(callback);
|
||||
m_http.MakePATCH("/guilds/" + std::to_string(id), nlohmann::json(obj).dump(), [this, signal](const cpr::Response &r) {
|
||||
const auto success = r.status_code == 200;
|
||||
signal.emit(success);
|
||||
});
|
||||
}
|
||||
|
||||
void DiscordClient::UpdateToken(std::string token) {
|
||||
if (!IsStarted()) {
|
||||
m_token = token;
|
||||
|
@ -110,6 +110,10 @@ public:
|
||||
std::optional<Snowflake> FindDM(Snowflake user_id); // wont find group dms
|
||||
void AddReaction(Snowflake id, Glib::ustring param);
|
||||
void RemoveReaction(Snowflake id, Glib::ustring param);
|
||||
void SetGuildName(Snowflake id, const Glib::ustring &name);
|
||||
void SetGuildName(Snowflake id, const Glib::ustring &name, sigc::slot<void(bool success)> callback);
|
||||
void SetGuildIcon(Snowflake id, const std::string &data);
|
||||
void SetGuildIcon(Snowflake id, const std::string &data, sigc::slot<void(bool success)> callback);
|
||||
|
||||
void UpdateToken(std::string token);
|
||||
void SetUserAgent(std::string agent);
|
||||
|
@ -118,6 +118,13 @@ void GuildData::update_from_json(const nlohmann::json &j) {
|
||||
JS_RD("approximate_presence_count", ApproximatePresenceCount);
|
||||
}
|
||||
|
||||
bool GuildData::HasFeature(const std::string &search_feature) {
|
||||
for (const auto &feature : Features)
|
||||
if (search_feature == feature)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GuildData::HasIcon() const {
|
||||
return Icon != "";
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ struct GuildData {
|
||||
friend void from_json(const nlohmann::json &j, GuildData &m);
|
||||
void update_from_json(const nlohmann::json &j);
|
||||
|
||||
bool HasFeature(const std::string &feature);
|
||||
bool HasIcon() const;
|
||||
bool HasAnimatedIcon() const;
|
||||
std::string GetIconURL(std::string ext = "png", std::string size = "32") const;
|
||||
|
@ -247,3 +247,8 @@ void from_json(const nlohmann::json &j, TypingStartObject &m) {
|
||||
JS_D("timestamp", m.Timestamp);
|
||||
JS_O("member", m.Member);
|
||||
}
|
||||
|
||||
void to_json(nlohmann::json &j, const ModifyGuildObject &m) {
|
||||
JS_IF("name", m.Name);
|
||||
JS_IF("icon", m.IconData);
|
||||
}
|
||||
|
@ -345,3 +345,11 @@ struct TypingStartObject {
|
||||
|
||||
friend void from_json(const nlohmann::json &j, TypingStartObject &m);
|
||||
};
|
||||
|
||||
// implement rest as needed
|
||||
struct ModifyGuildObject {
|
||||
std::optional<std::string> Name;
|
||||
std::optional<std::string> IconData;
|
||||
|
||||
friend void to_json(nlohmann::json &j, const ModifyGuildObject &m);
|
||||
};
|
||||
|
11
util.cpp
11
util.cpp
@ -100,8 +100,17 @@ std::string IntToCSSColor(int color) {
|
||||
}
|
||||
|
||||
void AddWidgetMenuHandler(Gtk::Widget *widget, Gtk::Menu &menu) {
|
||||
widget->signal_button_press_event().connect([&menu](GdkEventButton *ev) -> bool {
|
||||
AddWidgetMenuHandler(widget, menu, []() {});
|
||||
}
|
||||
|
||||
// so widgets can modify the menu before it is displayed
|
||||
// maybe theres a better way to do this idk
|
||||
void AddWidgetMenuHandler(Gtk::Widget *widget, Gtk::Menu &menu, sigc::slot<void()> pre_callback) {
|
||||
sigc::signal<void()> signal;
|
||||
signal.connect(pre_callback);
|
||||
widget->signal_button_press_event().connect([&menu, signal](GdkEventButton *ev) -> bool {
|
||||
if (ev->type == GDK_BUTTON_PRESS && ev->button == GDK_BUTTON_SECONDARY) {
|
||||
signal.emit();
|
||||
menu.popup_at_pointer(reinterpret_cast<const GdkEvent *>(ev));
|
||||
return true;
|
||||
}
|
||||
|
1
util.hpp
1
util.hpp
@ -39,6 +39,7 @@ void LaunchBrowser(Glib::ustring url);
|
||||
void GetImageDimensions(int inw, int inh, int &outw, int &outh, int clampw = 400, int clamph = 300);
|
||||
std::string IntToCSSColor(int color);
|
||||
void AddWidgetMenuHandler(Gtk::Widget *widget, Gtk::Menu &menu);
|
||||
void AddWidgetMenuHandler(Gtk::Widget *widget, Gtk::Menu &menu, sigc::slot<void()> pre_callback);
|
||||
std::vector<std::string> StringSplit(const std::string &str, const char *delim);
|
||||
std::string GetExtension(std::string url);
|
||||
bool IsURLViewableImage(const std::string &url);
|
||||
|
206
windows/guildsettings/infopane.cpp
Normal file
206
windows/guildsettings/infopane.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
#include "infopane.hpp"
|
||||
#include "../../abaddon.hpp"
|
||||
#include <filesystem>
|
||||
|
||||
GuildSettingsInfoPane::GuildSettingsInfoPane(Snowflake id)
|
||||
: GuildID(id)
|
||||
, m_guild_name_label("Guild name")
|
||||
, m_guild_icon_label("Guild icon") {
|
||||
auto &discord = Abaddon::Get().GetDiscordClient();
|
||||
const auto guild = *discord.GetGuild(id);
|
||||
const auto self_id = discord.GetUserData().ID;
|
||||
const auto can_modify = discord.HasGuildPermission(self_id, id, Permission::MANAGE_GUILD);
|
||||
|
||||
set_name("guild-info-pane");
|
||||
set_margin_top(10);
|
||||
set_margin_bottom(10);
|
||||
set_margin_left(10);
|
||||
set_margin_top(10);
|
||||
|
||||
m_guild_name.set_sensitive(can_modify);
|
||||
m_guild_name.set_text(guild.Name);
|
||||
m_guild_name.signal_focus_out_event().connect([this](GdkEventFocus *e) -> bool {
|
||||
UpdateGuildName();
|
||||
return false;
|
||||
});
|
||||
m_guild_name.signal_key_press_event().connect([this](GdkEventKey *e) -> bool {
|
||||
if (e->keyval == GDK_KEY_Return)
|
||||
UpdateGuildName();
|
||||
return false;
|
||||
// clang-format off
|
||||
}, false);
|
||||
// clang-format on
|
||||
m_guild_name.set_tooltip_text("Press enter or lose focus to submit");
|
||||
m_guild_name.show();
|
||||
m_guild_name_label.show();
|
||||
|
||||
auto load_icon_cb = [this](const Glib::RefPtr<Gdk::Pixbuf> &pixbuf) {
|
||||
m_guild_icon.property_pixbuf() = pixbuf->scale_simple(64, 64, Gdk::INTERP_BILINEAR);
|
||||
};
|
||||
|
||||
auto guild_update_cb = [this, load_icon_cb](Snowflake id) {
|
||||
if (id != GuildID) return;
|
||||
const auto guild = *Abaddon::Get().GetDiscordClient().GetGuild(id);
|
||||
if (guild.HasIcon())
|
||||
Abaddon::Get().GetImageManager().LoadFromURL(guild.GetIconURL("png", "64"), sigc::track_obj(load_icon_cb, *this));
|
||||
};
|
||||
discord.signal_guild_update().connect(sigc::track_obj(guild_update_cb, *this));
|
||||
|
||||
m_guild_icon.property_pixbuf() = Abaddon::Get().GetImageManager().GetPlaceholder(32);
|
||||
if (guild.HasIcon()) {
|
||||
Abaddon::Get().GetImageManager().LoadFromURL(guild.GetIconURL("png", "64"), sigc::track_obj(load_icon_cb, *this));
|
||||
}
|
||||
m_guild_icon.set_margin_bottom(10);
|
||||
if (can_modify) {
|
||||
m_guild_icon_ev.signal_realize().connect([this]() {
|
||||
auto window = m_guild_icon_ev.get_window();
|
||||
auto display = window->get_display();
|
||||
auto cursor = Gdk::Cursor::create(display, "pointer");
|
||||
window->set_cursor(cursor);
|
||||
});
|
||||
|
||||
m_guild_icon_ev.signal_button_press_event().connect([this](GdkEventButton *event) -> bool {
|
||||
if (event->type == GDK_BUTTON_PRESS)
|
||||
if (event->button == GDK_BUTTON_PRIMARY)
|
||||
UpdateGuildIconPicker();
|
||||
else if (event->button == GDK_BUTTON_SECONDARY)
|
||||
UpdateGuildIconClipboard();
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
m_guild_icon_ev.set_tooltip_text("Click to choose a file, right click to paste");
|
||||
m_guild_icon.show();
|
||||
m_guild_icon_ev.show();
|
||||
//m_guild_icon_label.show();
|
||||
|
||||
m_guild_icon_ev.add(m_guild_icon);
|
||||
attach(m_guild_icon_ev, 0, 0, 1, 1);
|
||||
attach(m_guild_name_label, 0, 1, 1, 1);
|
||||
attach_next_to(m_guild_name, m_guild_name_label, Gtk::POS_RIGHT, 1, 1);
|
||||
//attach(m_guild_icon_label, 0, 1, 1, 1);
|
||||
//attach_next_to(m_guild_icon, m_guild_icon_label, Gtk::POS_RIGHT, 1, 1);
|
||||
}
|
||||
|
||||
void GuildSettingsInfoPane::UpdateGuildName() {
|
||||
auto &discord = Abaddon::Get().GetDiscordClient();
|
||||
if (discord.GetGuild(GuildID)->Name == m_guild_name.get_text()) return;
|
||||
|
||||
auto cb = [this](bool success) {
|
||||
if (!success) {
|
||||
m_guild_name.set_text(Abaddon::Get().GetDiscordClient().GetGuild(GuildID)->Name);
|
||||
Gtk::MessageDialog dlg("Failed to set guild name", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
||||
dlg.run();
|
||||
}
|
||||
};
|
||||
discord.SetGuildName(GuildID, m_guild_name.get_text(), sigc::track_obj(cb, *this));
|
||||
}
|
||||
|
||||
void GuildSettingsInfoPane::UpdateGuildIconFromData(const std::vector<uint8_t> &data, const std::string &mime) {
|
||||
auto encoded = "data:" + mime + ";base64," + Glib::Base64::encode(std::string(data.begin(), data.end()));
|
||||
auto &discord = Abaddon::Get().GetDiscordClient();
|
||||
|
||||
auto cb = [this](bool success) {
|
||||
if (!success) {
|
||||
Gtk::MessageDialog dlg("Failed to set guild icon", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
||||
dlg.run();
|
||||
}
|
||||
};
|
||||
discord.SetGuildIcon(GuildID, encoded, sigc::track_obj(cb, *this));
|
||||
}
|
||||
|
||||
void GuildSettingsInfoPane::UpdateGuildIconFromPixbuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf) {
|
||||
int w = pixbuf->get_width();
|
||||
int h = pixbuf->get_height();
|
||||
if (w > 1024 || h > 1024) {
|
||||
GetImageDimensions(w, h, w, h, 1024, 1024);
|
||||
pixbuf = pixbuf->scale_simple(w, h, Gdk::INTERP_BILINEAR);
|
||||
}
|
||||
gchar *buffer;
|
||||
gsize buffer_size;
|
||||
pixbuf->save_to_buffer(buffer, buffer_size, "png");
|
||||
std::vector<uint8_t> data(buffer_size);
|
||||
std::memcpy(data.data(), buffer, buffer_size);
|
||||
UpdateGuildIconFromData(data, "image/png");
|
||||
}
|
||||
|
||||
void GuildSettingsInfoPane::UpdateGuildIconPicker() {
|
||||
// this picker fucking sucks
|
||||
Gtk::FileChooserDialog dlg("Choose new guild icon", Gtk::FILE_CHOOSER_ACTION_OPEN);
|
||||
dlg.get_style_context()->remove_provider(Abaddon::Get().GetStyleProvider());
|
||||
dlg.set_modal(true);
|
||||
dlg.signal_response().connect([this, &dlg](int response) {
|
||||
if (response == Gtk::RESPONSE_OK) {
|
||||
auto data = ReadWholeFile(dlg.get_filename());
|
||||
if (GetExtension(dlg.get_filename()) == ".gif")
|
||||
UpdateGuildIconFromData(data, "image/gif");
|
||||
else
|
||||
try {
|
||||
auto loader = Gdk::PixbufLoader::create();
|
||||
loader->signal_size_prepared().connect([&loader](int inw, int inh) {
|
||||
int w, h;
|
||||
GetImageDimensions(inw, inh, w, h, 1024, 1024);
|
||||
loader->set_size(w, h);
|
||||
});
|
||||
loader->write(data.data(), data.size());
|
||||
loader->close();
|
||||
UpdateGuildIconFromPixbuf(loader->get_pixbuf());
|
||||
} catch (const std::exception &) {};
|
||||
}
|
||||
});
|
||||
|
||||
dlg.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
|
||||
dlg.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
|
||||
|
||||
auto filter_images = Gtk::FileFilter::create();
|
||||
if (Abaddon::Get().GetDiscordClient().GetGuild(GuildID)->HasFeature("ANIMATED_ICON")) {
|
||||
filter_images->set_name("Supported images (*.jpg, *.jpeg, *.png, *.gif)");
|
||||
filter_images->add_pattern("*.gif");
|
||||
} else {
|
||||
filter_images->set_name("Supported images (*.jpg, *.jpeg, *.png)");
|
||||
}
|
||||
filter_images->add_pattern("*.jpg");
|
||||
filter_images->add_pattern("*.jpeg");
|
||||
filter_images->add_pattern("*.png");
|
||||
dlg.add_filter(filter_images);
|
||||
|
||||
auto filter_all = Gtk::FileFilter::create();
|
||||
filter_all->set_name("All files (*.*)");
|
||||
filter_all->add_pattern("*.*");
|
||||
dlg.add_filter(filter_all);
|
||||
|
||||
dlg.run();
|
||||
}
|
||||
|
||||
void GuildSettingsInfoPane::UpdateGuildIconClipboard() {
|
||||
std::vector<uint8_t> icon_data;
|
||||
|
||||
auto cb = Gtk::Clipboard::get();
|
||||
// query for file path then for actual image
|
||||
if (cb->wait_is_text_available()) {
|
||||
auto path = cb->wait_for_text();
|
||||
if (!std::filesystem::exists(path.c_str())) return;
|
||||
auto data = ReadWholeFile(path);
|
||||
try {
|
||||
auto loader = Gdk::PixbufLoader::create();
|
||||
loader->signal_size_prepared().connect([&loader](int inw, int inh) {
|
||||
int w, h;
|
||||
GetImageDimensions(inw, inh, w, h, 1024, 1024);
|
||||
loader->set_size(w, h);
|
||||
});
|
||||
loader->write(data.data(), data.size());
|
||||
loader->close();
|
||||
auto pb = loader->get_pixbuf();
|
||||
UpdateGuildIconFromPixbuf(pb);
|
||||
|
||||
return;
|
||||
} catch (const std::exception &) {};
|
||||
}
|
||||
|
||||
if (cb->wait_is_image_available()) {
|
||||
auto pb = cb->wait_for_image();
|
||||
UpdateGuildIconFromPixbuf(pb);
|
||||
return;
|
||||
}
|
||||
}
|
24
windows/guildsettings/infopane.hpp
Normal file
24
windows/guildsettings/infopane.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include <gtkmm.h>
|
||||
#include "../../discord/snowflake.hpp"
|
||||
|
||||
class GuildSettingsInfoPane : public Gtk::Grid {
|
||||
public:
|
||||
GuildSettingsInfoPane(Snowflake id);
|
||||
|
||||
private:
|
||||
void UpdateGuildName();
|
||||
void UpdateGuildIconFromData(const std::vector<uint8_t> &data, const std::string &mime);
|
||||
void UpdateGuildIconFromPixbuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf);
|
||||
void UpdateGuildIconPicker();
|
||||
void UpdateGuildIconClipboard();
|
||||
|
||||
Gtk::Label m_guild_icon_label;
|
||||
Gtk::EventBox m_guild_icon_ev; // necessary to make custom cursor behave properly
|
||||
Gtk::Image m_guild_icon;
|
||||
|
||||
Gtk::Label m_guild_name_label;
|
||||
Gtk::Entry m_guild_name;
|
||||
|
||||
Snowflake GuildID;
|
||||
};
|
45
windows/guildsettingswindow.cpp
Normal file
45
windows/guildsettingswindow.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include "guildsettingswindow.hpp"
|
||||
#include "../abaddon.hpp"
|
||||
|
||||
GuildSettingsWindow::GuildSettingsWindow(Snowflake id)
|
||||
: m_main(Gtk::ORIENTATION_VERTICAL)
|
||||
, GuildID(id)
|
||||
, m_pane_info(id) {
|
||||
auto &discord = Abaddon::Get().GetDiscordClient();
|
||||
const auto guild = *discord.GetGuild(id);
|
||||
|
||||
auto guild_update_cb = [this](Snowflake id) {
|
||||
if (id != GuildID) return;
|
||||
const auto guild = *Abaddon::Get().GetDiscordClient().GetGuild(id);
|
||||
set_title(guild.Name);
|
||||
if (guild.HasIcon())
|
||||
Abaddon::Get().GetImageManager().LoadFromURL(guild.GetIconURL(), sigc::mem_fun(*this, &GuildSettingsWindow::set_icon));
|
||||
};
|
||||
discord.signal_guild_update().connect(sigc::track_obj(guild_update_cb, *this));
|
||||
|
||||
set_name("guild-settings");
|
||||
set_default_size(800, 600);
|
||||
set_title(guild.Name);
|
||||
set_position(Gtk::WIN_POS_CENTER);
|
||||
get_style_context()->add_class("app-window");
|
||||
|
||||
if (guild.HasIcon()) {
|
||||
Abaddon::Get().GetImageManager().LoadFromURL(guild.GetIconURL(), sigc::mem_fun(*this, &GuildSettingsWindow::set_icon));
|
||||
}
|
||||
|
||||
m_switcher.set_stack(m_stack);
|
||||
m_switcher.set_halign(Gtk::ALIGN_CENTER);
|
||||
m_switcher.set_hexpand(true);
|
||||
m_switcher.set_margin_top(10);
|
||||
m_switcher.show();
|
||||
|
||||
m_pane_info.show();
|
||||
|
||||
m_stack.add(m_pane_info, "info", "Info");
|
||||
m_stack.show();
|
||||
|
||||
m_main.add(m_switcher);
|
||||
m_main.add(m_stack);
|
||||
m_main.show();
|
||||
add(m_main);
|
||||
}
|
18
windows/guildsettingswindow.hpp
Normal file
18
windows/guildsettingswindow.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include <gtkmm.h>
|
||||
#include "../discord/snowflake.hpp"
|
||||
#include "guildsettings/infopane.hpp"
|
||||
|
||||
class GuildSettingsWindow : public Gtk::Window {
|
||||
public:
|
||||
GuildSettingsWindow(Snowflake id);
|
||||
|
||||
private:
|
||||
Gtk::Box m_main;
|
||||
Gtk::Stack m_stack;
|
||||
Gtk::StackSwitcher m_switcher;
|
||||
|
||||
GuildSettingsInfoPane m_pane_info;
|
||||
|
||||
Snowflake GuildID;
|
||||
};
|
@ -7,6 +7,7 @@ MainWindow::MainWindow()
|
||||
, m_chan_chat_paned(Gtk::ORIENTATION_HORIZONTAL)
|
||||
, m_chat_members_paned(Gtk::ORIENTATION_HORIZONTAL) {
|
||||
set_default_size(1200, 800);
|
||||
get_style_context()->add_class("app-window");
|
||||
|
||||
m_menu_discord.set_label("Discord");
|
||||
m_menu_discord.set_submenu(m_menu_discord_sub);
|
||||
|
Loading…
Reference in New Issue
Block a user