mirror of
https://github.com/celisej567/abaddon.git
synced 2026-09-27 16:16:35 +03:00
add animated guild icons to channel list
This commit is contained in:
@@ -190,9 +190,12 @@ For example, memory_db would be set by adding `memory_db = true` under the line
|
|||||||
* custom_emojis (true or false, default true) - download and use custom Discord emojis
|
* custom_emojis (true or false, default true) - download and use custom Discord emojis
|
||||||
* css (string) - path to the main CSS file
|
* css (string) - path to the main CSS file
|
||||||
* animations (true or false, default true) - use animated images where available (e.g. server icons, emojis, avatars). false means static images will be used
|
* animations (true or false, default true) - use animated images where available (e.g. server icons, emojis, avatars). false means static images will be used
|
||||||
|
* animated_guild_hover_only (true or false, default true) - only animate guild icons when the guild is being hovered over
|
||||||
* owner_crown (true or false, default true) - show a crown next to the owner
|
* owner_crown (true or false, default true) - show a crown next to the owner
|
||||||
* gateway (string) - override url for Discord gateway. must be json format and use zlib stream compression
|
* gateway (string) - override url for Discord gateway. must be json format and use zlib stream compression
|
||||||
* api_base (string) - override base url for Discord API
|
* api_base (string) - override base url for Discord API
|
||||||
|
|
||||||
#### misc
|
#### style
|
||||||
* linkcolor (string) - color to use for links in messages
|
* linkcolor (string) - color to use for links in messages
|
||||||
|
* expandercolor (string) - color to use for the expander in the channel list
|
||||||
|
* nsfwchannelcolor (string) - color to use for NSFW channels in the channel list
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include "statusindicator.hpp"
|
#include "statusindicator.hpp"
|
||||||
|
|
||||||
ChannelList::ChannelList()
|
ChannelList::ChannelList()
|
||||||
: Glib::ObjectBase("channellist")
|
: Glib::ObjectBase(typeid(ChannelList))
|
||||||
, Gtk::ScrolledWindow()
|
, Gtk::ScrolledWindow()
|
||||||
, m_model(Gtk::TreeStore::create(m_columns))
|
, m_model(Gtk::TreeStore::create(m_columns))
|
||||||
, m_menu_guild_copy_id("_Copy ID", true)
|
, m_menu_guild_copy_id("_Copy ID", true)
|
||||||
@@ -66,6 +66,7 @@ ChannelList::ChannelList()
|
|||||||
column->pack_start(*renderer);
|
column->pack_start(*renderer);
|
||||||
column->add_attribute(renderer->property_type(), m_columns.m_type);
|
column->add_attribute(renderer->property_type(), m_columns.m_type);
|
||||||
column->add_attribute(renderer->property_icon(), m_columns.m_icon);
|
column->add_attribute(renderer->property_icon(), m_columns.m_icon);
|
||||||
|
column->add_attribute(renderer->property_icon_animation(), m_columns.m_icon_anim);
|
||||||
column->add_attribute(renderer->property_name(), m_columns.m_name);
|
column->add_attribute(renderer->property_name(), m_columns.m_name);
|
||||||
column->add_attribute(renderer->property_expanded(), m_columns.m_expanded);
|
column->add_attribute(renderer->property_expanded(), m_columns.m_expanded);
|
||||||
column->add_attribute(renderer->property_nsfw(), m_columns.m_nsfw);
|
column->add_attribute(renderer->property_nsfw(), m_columns.m_nsfw);
|
||||||
@@ -235,14 +236,21 @@ void ChannelList::UpdateGuild(Snowflake id) {
|
|||||||
const auto guild = Abaddon::Get().GetDiscordClient().GetGuild(id);
|
const auto guild = Abaddon::Get().GetDiscordClient().GetGuild(id);
|
||||||
if (!iter || !guild.has_value()) return;
|
if (!iter || !guild.has_value()) return;
|
||||||
|
|
||||||
|
static const bool show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
|
||||||
|
|
||||||
(*iter)[m_columns.m_name] = "<b>" + Glib::Markup::escape_text(guild->Name) + "</b>";
|
(*iter)[m_columns.m_name] = "<b>" + Glib::Markup::escape_text(guild->Name) + "</b>";
|
||||||
(*iter)[m_columns.m_icon] = img.GetPlaceholder(GuildIconSize);
|
(*iter)[m_columns.m_icon] = img.GetPlaceholder(GuildIconSize);
|
||||||
if (guild->HasIcon()) {
|
if (show_animations && guild->HasAnimatedIcon()) {
|
||||||
|
const auto cb = [this, id](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
|
||||||
|
auto iter = GetIteratorForGuildFromID(id);
|
||||||
|
if (iter) (*iter)[m_columns.m_icon_anim] = pb;
|
||||||
|
};
|
||||||
|
img.LoadAnimationFromURL(guild->GetIconURL("gif", "32"), GuildIconSize, GuildIconSize, sigc::track_obj(cb, *this));
|
||||||
|
} else if (guild->HasIcon()) {
|
||||||
const auto cb = [this, id](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
|
const auto cb = [this, id](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
|
||||||
// iter might be invalid
|
// iter might be invalid
|
||||||
auto iter = GetIteratorForGuildFromID(id);
|
auto iter = GetIteratorForGuildFromID(id);
|
||||||
if (iter)
|
if (iter) (*iter)[m_columns.m_icon] = pb->scale_simple(GuildIconSize, GuildIconSize, Gdk::INTERP_BILINEAR);
|
||||||
(*iter)[m_columns.m_icon] = pb->scale_simple(GuildIconSize, GuildIconSize, Gdk::INTERP_BILINEAR);
|
|
||||||
};
|
};
|
||||||
img.LoadFromURL(guild->GetIconURL("png", "32"), sigc::track_obj(cb, *this));
|
img.LoadFromURL(guild->GetIconURL("png", "32"), sigc::track_obj(cb, *this));
|
||||||
}
|
}
|
||||||
@@ -266,11 +274,18 @@ Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild) {
|
|||||||
guild_row[m_columns.m_name] = "<b>" + Glib::Markup::escape_text(guild.Name) + "</b>";
|
guild_row[m_columns.m_name] = "<b>" + Glib::Markup::escape_text(guild.Name) + "</b>";
|
||||||
guild_row[m_columns.m_icon] = img.GetPlaceholder(GuildIconSize);
|
guild_row[m_columns.m_icon] = img.GetPlaceholder(GuildIconSize);
|
||||||
|
|
||||||
if (guild.HasIcon()) {
|
static const bool show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
|
||||||
|
|
||||||
|
if (show_animations && guild.HasAnimatedIcon()) {
|
||||||
|
const auto cb = [this, id = guild.ID](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
|
||||||
|
auto iter = GetIteratorForGuildFromID(id);
|
||||||
|
if (iter) (*iter)[m_columns.m_icon_anim] = pb;
|
||||||
|
};
|
||||||
|
img.LoadAnimationFromURL(guild.GetIconURL("gif", "32"), GuildIconSize, GuildIconSize, sigc::track_obj(cb, *this));
|
||||||
|
} else if (guild.HasIcon()) {
|
||||||
const auto cb = [this, id = guild.ID](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
|
const auto cb = [this, id = guild.ID](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
|
||||||
auto iter = GetIteratorForGuildFromID(id);
|
auto iter = GetIteratorForGuildFromID(id);
|
||||||
if (iter)
|
if (iter) (*iter)[m_columns.m_icon] = pb->scale_simple(GuildIconSize, GuildIconSize, Gdk::INTERP_BILINEAR);
|
||||||
(*iter)[m_columns.m_icon] = pb->scale_simple(GuildIconSize, GuildIconSize, Gdk::INTERP_BILINEAR);
|
|
||||||
};
|
};
|
||||||
img.LoadFromURL(guild.GetIconURL("png", "32"), sigc::track_obj(cb, *this));
|
img.LoadFromURL(guild.GetIconURL("png", "32"), sigc::track_obj(cb, *this));
|
||||||
}
|
}
|
||||||
@@ -537,6 +552,7 @@ ChannelList::ModelColumns::ModelColumns() {
|
|||||||
add(m_id);
|
add(m_id);
|
||||||
add(m_name);
|
add(m_name);
|
||||||
add(m_icon);
|
add(m_icon);
|
||||||
|
add(m_icon_anim);
|
||||||
add(m_sort);
|
add(m_sort);
|
||||||
add(m_nsfw);
|
add(m_nsfw);
|
||||||
add(m_expanded);
|
add(m_expanded);
|
||||||
@@ -548,6 +564,7 @@ CellRendererChannels::CellRendererChannels()
|
|||||||
, m_property_type(*this, "render-type")
|
, m_property_type(*this, "render-type")
|
||||||
, m_property_name(*this, "name")
|
, m_property_name(*this, "name")
|
||||||
, m_property_pixbuf(*this, "pixbuf")
|
, m_property_pixbuf(*this, "pixbuf")
|
||||||
|
, m_property_pixbuf_animation(*this, "pixbuf-animation")
|
||||||
, m_property_expanded(*this, "expanded")
|
, m_property_expanded(*this, "expanded")
|
||||||
, m_property_nsfw(*this, "nsfw") {
|
, m_property_nsfw(*this, "nsfw") {
|
||||||
property_mode() = Gtk::CELL_RENDERER_MODE_ACTIVATABLE;
|
property_mode() = Gtk::CELL_RENDERER_MODE_ACTIVATABLE;
|
||||||
@@ -573,6 +590,10 @@ Glib::PropertyProxy<Glib::RefPtr<Gdk::Pixbuf>> CellRendererChannels::property_ic
|
|||||||
return m_property_pixbuf.get_proxy();
|
return m_property_pixbuf.get_proxy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Glib::PropertyProxy<Glib::RefPtr<Gdk::PixbufAnimation>> CellRendererChannels::property_icon_animation() {
|
||||||
|
return m_property_pixbuf_animation.get_proxy();
|
||||||
|
}
|
||||||
|
|
||||||
Glib::PropertyProxy<bool> CellRendererChannels::property_expanded() {
|
Glib::PropertyProxy<bool> CellRendererChannels::property_expanded() {
|
||||||
return m_property_expanded.get_proxy();
|
return m_property_expanded.get_proxy();
|
||||||
}
|
}
|
||||||
@@ -660,7 +681,10 @@ void CellRendererChannels::render_vfunc(const Cairo::RefPtr<Cairo::Context> &cr,
|
|||||||
|
|
||||||
void CellRendererChannels::get_preferred_width_vfunc_guild(Gtk::Widget &widget, int &minimum_width, int &natural_width) const {
|
void CellRendererChannels::get_preferred_width_vfunc_guild(Gtk::Widget &widget, int &minimum_width, int &natural_width) const {
|
||||||
int pixbuf_width = 0;
|
int pixbuf_width = 0;
|
||||||
if (auto pixbuf = m_property_pixbuf.get_value())
|
|
||||||
|
if (auto pixbuf = m_property_pixbuf_animation.get_value())
|
||||||
|
pixbuf_width = pixbuf->get_width();
|
||||||
|
else if (auto pixbuf = m_property_pixbuf.get_value())
|
||||||
pixbuf_width = pixbuf->get_width();
|
pixbuf_width = pixbuf->get_width();
|
||||||
|
|
||||||
int text_min, text_nat;
|
int text_min, text_nat;
|
||||||
@@ -678,7 +702,9 @@ void CellRendererChannels::get_preferred_width_for_height_vfunc_guild(Gtk::Widge
|
|||||||
|
|
||||||
void CellRendererChannels::get_preferred_height_vfunc_guild(Gtk::Widget &widget, int &minimum_height, int &natural_height) const {
|
void CellRendererChannels::get_preferred_height_vfunc_guild(Gtk::Widget &widget, int &minimum_height, int &natural_height) const {
|
||||||
int pixbuf_height = 0;
|
int pixbuf_height = 0;
|
||||||
if (auto pixbuf = m_property_pixbuf.get_value())
|
if (auto pixbuf = m_property_pixbuf_animation.get_value())
|
||||||
|
pixbuf_height = pixbuf->get_height();
|
||||||
|
else if (auto pixbuf = m_property_pixbuf.get_value())
|
||||||
pixbuf_height = pixbuf->get_height();
|
pixbuf_height = pixbuf->get_height();
|
||||||
|
|
||||||
int text_min, text_nat;
|
int text_min, text_nat;
|
||||||
@@ -701,10 +727,17 @@ void CellRendererChannels::render_vfunc_guild(const Cairo::RefPtr<Cairo::Context
|
|||||||
Gtk::Requisition minimum, natural;
|
Gtk::Requisition minimum, natural;
|
||||||
get_preferred_size(widget, minimum, natural);
|
get_preferred_size(widget, minimum, natural);
|
||||||
|
|
||||||
auto pixbuf = m_property_pixbuf.get_value();
|
int pixbuf_w, pixbuf_h = 0;
|
||||||
|
if (auto pixbuf = m_property_pixbuf_animation.get_value()) {
|
||||||
|
pixbuf_w = pixbuf->get_width();
|
||||||
|
pixbuf_h = pixbuf->get_height();
|
||||||
|
} else if (auto pixbuf = m_property_pixbuf.get_value()) {
|
||||||
|
pixbuf_w = pixbuf->get_width();
|
||||||
|
pixbuf_h = pixbuf->get_height();
|
||||||
|
}
|
||||||
|
|
||||||
const double icon_w = pixbuf->get_width();
|
const double icon_w = pixbuf_w;
|
||||||
const double icon_h = pixbuf->get_height();
|
const double icon_h = pixbuf_h;
|
||||||
const double icon_x = background_area.get_x();
|
const double icon_x = background_area.get_x();
|
||||||
const double icon_y = background_area.get_y() + background_area.get_height() / 2.0 - icon_h / 2.0;
|
const double icon_y = background_area.get_y() + background_area.get_height() / 2.0 - icon_h / 2.0;
|
||||||
|
|
||||||
@@ -717,9 +750,35 @@ void CellRendererChannels::render_vfunc_guild(const Cairo::RefPtr<Cairo::Context
|
|||||||
|
|
||||||
m_renderer_text.render(cr, widget, background_area, text_cell_area, flags);
|
m_renderer_text.render(cr, widget, background_area, text_cell_area, flags);
|
||||||
|
|
||||||
Gdk::Cairo::set_source_pixbuf(cr, m_property_pixbuf.get_value(), icon_x, icon_y);
|
const static bool hover_only = Abaddon::Get().GetSettings().GetAnimatedGuildHoverOnly();
|
||||||
cr->rectangle(icon_x, icon_y, icon_w, icon_h);
|
const bool is_hovered = flags & Gtk::CELL_RENDERER_PRELIT;
|
||||||
cr->fill();
|
auto anim = m_property_pixbuf_animation.get_value();
|
||||||
|
|
||||||
|
// kinda gross
|
||||||
|
if (anim) {
|
||||||
|
auto map_iter = m_pixbuf_anim_iters.find(anim);
|
||||||
|
if (map_iter == m_pixbuf_anim_iters.end())
|
||||||
|
m_pixbuf_anim_iters[anim] = anim->get_iter(nullptr);
|
||||||
|
auto pb_iter = m_pixbuf_anim_iters.at(anim);
|
||||||
|
|
||||||
|
const auto cb = [this, &widget, anim, icon_x, icon_y, icon_w, icon_h] {
|
||||||
|
if (m_pixbuf_anim_iters.at(anim)->advance())
|
||||||
|
widget.queue_draw_area(icon_x, icon_y, icon_w, icon_h);
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((hover_only && is_hovered) || !hover_only)
|
||||||
|
Glib::signal_timeout().connect_once(sigc::track_obj(cb, widget), pb_iter->get_delay_time());
|
||||||
|
if (hover_only && !is_hovered)
|
||||||
|
m_pixbuf_anim_iters[anim] = anim->get_iter(nullptr);
|
||||||
|
|
||||||
|
Gdk::Cairo::set_source_pixbuf(cr, pb_iter->get_pixbuf(), icon_x, icon_y);
|
||||||
|
cr->rectangle(icon_x, icon_y, icon_w, icon_h);
|
||||||
|
cr->fill();
|
||||||
|
} else if (auto pixbuf = m_property_pixbuf.get_value()) {
|
||||||
|
Gdk::Cairo::set_source_pixbuf(cr, pixbuf, icon_x, icon_y);
|
||||||
|
cr->rectangle(icon_x, icon_y, icon_w, icon_h);
|
||||||
|
cr->fill();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// category
|
// category
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public:
|
|||||||
Glib::PropertyProxy<RenderType> property_type();
|
Glib::PropertyProxy<RenderType> property_type();
|
||||||
Glib::PropertyProxy<Glib::ustring> property_name();
|
Glib::PropertyProxy<Glib::ustring> property_name();
|
||||||
Glib::PropertyProxy<Glib::RefPtr<Gdk::Pixbuf>> property_icon();
|
Glib::PropertyProxy<Glib::RefPtr<Gdk::Pixbuf>> property_icon();
|
||||||
|
Glib::PropertyProxy<Glib::RefPtr<Gdk::PixbufAnimation>> property_icon_animation();
|
||||||
Glib::PropertyProxy<bool> property_expanded();
|
Glib::PropertyProxy<bool> property_expanded();
|
||||||
Glib::PropertyProxy<bool> property_nsfw();
|
Glib::PropertyProxy<bool> property_nsfw();
|
||||||
|
|
||||||
@@ -101,11 +102,17 @@ protected:
|
|||||||
private:
|
private:
|
||||||
Gtk::CellRendererText m_renderer_text;
|
Gtk::CellRendererText m_renderer_text;
|
||||||
|
|
||||||
Glib::Property<RenderType> m_property_type; // all
|
Glib::Property<RenderType> m_property_type; // all
|
||||||
Glib::Property<Glib::ustring> m_property_name; // all
|
Glib::Property<Glib::ustring> m_property_name; // all
|
||||||
Glib::Property<Glib::RefPtr<Gdk::Pixbuf>> m_property_pixbuf; // guild, dm
|
Glib::Property<Glib::RefPtr<Gdk::Pixbuf>> m_property_pixbuf; // guild, dm
|
||||||
Glib::Property<bool> m_property_expanded; // category
|
Glib::Property<Glib::RefPtr<Gdk::PixbufAnimation>> m_property_pixbuf_animation; // guild
|
||||||
Glib::Property<bool> m_property_nsfw; // channel
|
Glib::Property<bool> m_property_expanded; // category
|
||||||
|
Glib::Property<bool> m_property_nsfw; // channel
|
||||||
|
|
||||||
|
// same pitfalls as in https://github.com/uowuo/abaddon/blob/60404783bd4ce9be26233fe66fc3a74475d9eaa3/components/cellrendererpixbufanimation.hpp#L32-L39
|
||||||
|
// this will manifest though since guild icons can change
|
||||||
|
// an animation or two wont be the end of the world though
|
||||||
|
std::map<Glib::RefPtr<Gdk::PixbufAnimation>, Glib::RefPtr<Gdk::PixbufAnimationIter>> m_pixbuf_anim_iters;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ChannelList : public Gtk::ScrolledWindow {
|
class ChannelList : public Gtk::ScrolledWindow {
|
||||||
@@ -132,6 +139,7 @@ protected:
|
|||||||
Gtk::TreeModelColumn<uint64_t> m_id;
|
Gtk::TreeModelColumn<uint64_t> m_id;
|
||||||
Gtk::TreeModelColumn<Glib::ustring> m_name;
|
Gtk::TreeModelColumn<Glib::ustring> m_name;
|
||||||
Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf>> m_icon;
|
Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf>> m_icon;
|
||||||
|
Gtk::TreeModelColumn<Glib::RefPtr<Gdk::PixbufAnimation>> m_icon_anim;
|
||||||
Gtk::TreeModelColumn<int64_t> m_sort;
|
Gtk::TreeModelColumn<int64_t> m_sort;
|
||||||
Gtk::TreeModelColumn<bool> m_nsfw;
|
Gtk::TreeModelColumn<bool> m_nsfw;
|
||||||
// Gtk::CellRenderer's property_is_expanded only works how i want it to if it has children
|
// Gtk::CellRenderer's property_is_expanded only works how i want it to if it has children
|
||||||
|
|||||||
@@ -101,3 +101,7 @@ std::string SettingsManager::GetGatewayURL() const {
|
|||||||
std::string SettingsManager::GetAPIBaseURL() const {
|
std::string SettingsManager::GetAPIBaseURL() const {
|
||||||
return GetSettingString("discord", "api_base", "https://discord.com/api/v9");
|
return GetSettingString("discord", "api_base", "https://discord.com/api/v9");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SettingsManager::GetAnimatedGuildHoverOnly() const {
|
||||||
|
return GetSettingBool("gui", "animated_guild_hover_only", true);
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public:
|
|||||||
bool GetShowOwnerCrown() const;
|
bool GetShowOwnerCrown() const;
|
||||||
std::string GetGatewayURL() const;
|
std::string GetGatewayURL() const;
|
||||||
std::string GetAPIBaseURL() const;
|
std::string GetAPIBaseURL() const;
|
||||||
|
bool GetAnimatedGuildHoverOnly() const;
|
||||||
|
|
||||||
// i would like to use Gtk::StyleProperty for this, but it will not work on windows
|
// i would like to use Gtk::StyleProperty for this, but it will not work on windows
|
||||||
// #1 it's missing from the project files for the version used by vcpkg
|
// #1 it's missing from the project files for the version used by vcpkg
|
||||||
|
|||||||
Reference in New Issue
Block a user