summaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
authorouwou <26526779+ouwou@users.noreply.github.com>2023-05-14 23:55:38 -0400
committerouwou <26526779+ouwou@users.noreply.github.com>2023-05-14 23:55:38 -0400
commitd0fa9cc289d8398a27ddf2a66783b5d460e2210a (patch)
treead98161438282800927556cba438e8ded6fbbed2 /src/components
parent49f6cd021beb70a2f9e8c359275af69922bffb83 (diff)
downloadabaddon-portaudio-d0fa9cc289d8398a27ddf2a66783b5d460e2210a.tar.gz
abaddon-portaudio-d0fa9cc289d8398a27ddf2a66783b5d460e2210a.zip
make voice channel list UI look better
Diffstat (limited to 'src/components')
-rw-r--r--src/components/channels.cpp61
-rw-r--r--src/components/channels.hpp2
-rw-r--r--src/components/channelscellrenderer.cpp84
3 files changed, 103 insertions, 44 deletions
diff --git a/src/components/channels.cpp b/src/components/channels.cpp
index 9cb8b09..3327b02 100644
--- a/src/components/channels.cpp
+++ b/src/components/channels.cpp
@@ -42,11 +42,7 @@ ChannelList::ChannelList()
const auto type = row[m_columns.m_type];
// text channels should not be allowed to be collapsed
// maybe they should be but it seems a little difficult to handle expansion to permit this
-#ifdef WITH_VOICE
- if (type != RenderType::TextChannel && type != RenderType::VoiceChannel) {
-#else
if (type != RenderType::TextChannel) {
-#endif
if (row[m_columns.m_expanded]) {
m_view.collapse_row(path);
row[m_columns.m_expanded] = false;
@@ -56,11 +52,7 @@ ChannelList::ChannelList()
}
}
-#ifdef WITH_VOICE
- if (type == RenderType::TextChannel || type == RenderType::DM || type == RenderType::Thread || type == RenderType::VoiceChannel) {
-#else
if (type == RenderType::TextChannel || type == RenderType::DM || type == RenderType::Thread) {
-#endif
const auto id = static_cast<Snowflake>(row[m_columns.m_id]);
m_signal_action_channel_item_select.emit(id);
Abaddon::Get().GetDiscordClient().MarkChannelAsRead(id, [](...) {});
@@ -537,14 +529,7 @@ void ChannelList::OnVoiceUserConnect(Snowflake user_id, Snowflake channel_id) {
const auto user = Abaddon::Get().GetDiscordClient().GetUser(user_id);
if (!user.has_value()) return;
- auto user_row = *m_model->append(parent_iter->children());
- user_row[m_columns.m_type] = RenderType::VoiceParticipant;
- user_row[m_columns.m_id] = user_id;
- if (user.has_value()) {
- user_row[m_columns.m_name] = user->GetEscapedName();
- } else {
- user_row[m_columns.m_name] = "<i>Unknown</i>";
- }
+ CreateVoiceParticipantRow(*user, parent_iter->children());
}
void ChannelList::OnVoiceUserDisconnect(Snowflake user_id, Snowflake channel_id) {
@@ -776,15 +761,8 @@ Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild, const Gtk
#ifdef WITH_VOICE
auto add_voice_participants = [this, &discord](const ChannelData &channel, const Gtk::TreeNodeChildren &root) {
for (auto user_id : discord.GetUsersInVoiceChannel(channel.ID)) {
- const auto user = discord.GetUser(user_id);
-
- auto user_row = *m_model->append(root);
- user_row[m_columns.m_type] = RenderType::VoiceParticipant;
- user_row[m_columns.m_id] = user_id;
- if (user.has_value()) {
- user_row[m_columns.m_name] = user->GetEscapedName();
- } else {
- user_row[m_columns.m_name] = "<i>Unknown</i>";
+ if (const auto user = discord.GetUser(user_id); user.has_value()) {
+ CreateVoiceParticipantRow(*user, root);
}
}
};
@@ -792,16 +770,18 @@ Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild, const Gtk
for (const auto &channel : orphan_channels) {
auto channel_row = *m_model->append(guild_row.children());
- if (IsTextChannel(channel.Type))
+ if (IsTextChannel(channel.Type)) {
channel_row[m_columns.m_type] = RenderType::TextChannel;
+ channel_row[m_columns.m_name] = "#" + Glib::Markup::escape_text(*channel.Name);
+ }
#ifdef WITH_VOICE
else {
channel_row[m_columns.m_type] = RenderType::VoiceChannel;
+ channel_row[m_columns.m_name] = Glib::Markup::escape_text(*channel.Name);
add_voice_participants(channel, channel_row->children());
}
#endif
channel_row[m_columns.m_id] = channel.ID;
- channel_row[m_columns.m_name] = "#" + Glib::Markup::escape_text(*channel.Name);
channel_row[m_columns.m_sort] = *channel.Position + OrphanChannelSortOffset;
channel_row[m_columns.m_nsfw] = channel.NSFW();
add_threads(channel, channel_row);
@@ -822,16 +802,18 @@ Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild, const Gtk
for (const auto &channel : channels) {
auto channel_row = *m_model->append(cat_row.children());
- if (IsTextChannel(channel.Type))
+ if (IsTextChannel(channel.Type)) {
channel_row[m_columns.m_type] = RenderType::TextChannel;
+ channel_row[m_columns.m_name] = "#" + Glib::Markup::escape_text(*channel.Name);
+ }
#ifdef WITH_VOICE
else {
channel_row[m_columns.m_type] = RenderType::VoiceChannel;
+ channel_row[m_columns.m_name] = Glib::Markup::escape_text(*channel.Name);
add_voice_participants(channel, channel_row->children());
}
#endif
channel_row[m_columns.m_id] = channel.ID;
- channel_row[m_columns.m_name] = "#" + Glib::Markup::escape_text(*channel.Name);
channel_row[m_columns.m_sort] = *channel.Position;
channel_row[m_columns.m_nsfw] = channel.NSFW();
add_threads(channel, channel_row);
@@ -868,6 +850,23 @@ Gtk::TreeModel::iterator ChannelList::CreateThreadRow(const Gtk::TreeNodeChildre
return thread_iter;
}
+Gtk::TreeModel::iterator ChannelList::CreateVoiceParticipantRow(const UserData &user, const Gtk::TreeNodeChildren &parent) {
+ auto row = *m_model->append(parent);
+ row[m_columns.m_type] = RenderType::VoiceParticipant;
+ row[m_columns.m_id] = user.ID;
+ row[m_columns.m_name] = user.GetEscapedName();
+
+ auto &img = Abaddon::Get().GetImageManager();
+ row[m_columns.m_icon] = img.GetPlaceholder(VoiceParticipantIconSize);
+ const auto cb = [this, user_id = user.ID](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
+ auto iter = GetIteratorForRowFromIDOfType(user_id, RenderType::VoiceParticipant);
+ if (iter) (*iter)[m_columns.m_icon] = pb->scale_simple(VoiceParticipantIconSize, VoiceParticipantIconSize, Gdk::INTERP_BILINEAR);
+ };
+ img.LoadFromURL(user.GetAvatarURL("png", "32"), sigc::track_obj(cb, *this));
+
+ return row;
+}
+
void ChannelList::UpdateChannelCategory(const ChannelData &channel) {
auto iter = GetIteratorForRowFromID(channel.ID);
if (!iter) return;
@@ -971,11 +970,7 @@ bool ChannelList::SelectionFunc(const Glib::RefPtr<Gtk::TreeModel> &model, const
m_last_selected = m_model->get_path(row);
auto type = (*m_model->get_iter(path))[m_columns.m_type];
-#ifdef WITH_VOICE
- return type == RenderType::TextChannel || type == RenderType::DM || type == RenderType::Thread || type == RenderType::VoiceChannel;
-#else
return type == RenderType::TextChannel || type == RenderType::DM || type == RenderType::Thread;
-#endif
}
void ChannelList::AddPrivateChannels() {
diff --git a/src/components/channels.hpp b/src/components/channels.hpp
index 36c7766..8aee733 100644
--- a/src/components/channels.hpp
+++ b/src/components/channels.hpp
@@ -16,6 +16,7 @@
constexpr static int GuildIconSize = 24;
constexpr static int DMIconSize = 20;
+constexpr static int VoiceParticipantIconSize = 18;
constexpr static int OrphanChannelSortOffset = -100; // forces orphan channels to the top of the list
class ChannelList : public Gtk::ScrolledWindow {
@@ -84,6 +85,7 @@ protected:
Gtk::TreeModel::iterator AddGuild(const GuildData &guild, const Gtk::TreeNodeChildren &root);
Gtk::TreeModel::iterator UpdateCreateChannelCategory(const ChannelData &channel);
Gtk::TreeModel::iterator CreateThreadRow(const Gtk::TreeNodeChildren &children, const ChannelData &channel);
+ Gtk::TreeModel::iterator CreateVoiceParticipantRow(const UserData &user, const Gtk::TreeNodeChildren &parent);
void UpdateChannelCategory(const ChannelData &channel);
diff --git a/src/components/channelscellrenderer.cpp b/src/components/channelscellrenderer.cpp
index fb82682..ab3113c 100644
--- a/src/components/channelscellrenderer.cpp
+++ b/src/components/channelscellrenderer.cpp
@@ -626,18 +626,58 @@ void CellRendererChannels::get_preferred_height_for_width_vfunc_voice_channel(Gt
}
void CellRendererChannels::render_vfunc_voice_channel(const Cairo::RefPtr<Cairo::Context> &cr, Gtk::Widget &widget, const Gdk::Rectangle &background_area, const Gdk::Rectangle &cell_area, Gtk::CellRendererState flags) {
+ // channel name text
Gtk::Requisition minimum_size, natural_size;
m_renderer_text.get_preferred_size(widget, minimum_size, natural_size);
- const int text_x = background_area.get_x() + 21;
+ const int text_x = background_area.get_x() + 35;
const int text_y = background_area.get_y() + background_area.get_height() / 2 - natural_size.height / 2;
const int text_w = natural_size.width;
const int text_h = natural_size.height;
Gdk::Rectangle text_cell_area(text_x, text_y, text_w, text_h);
- m_renderer_text.property_foreground_rgba() = Gdk::RGBA("#0f0");
m_renderer_text.render(cr, widget, background_area, text_cell_area, flags);
- m_renderer_text.property_foreground_set() = false;
+
+ // speaker character
+ Pango::FontDescription font;
+ font.set_family("sans 14");
+
+ auto layout = widget.create_pango_layout("\U0001F50A");
+ layout->set_font_description(font);
+ layout->set_alignment(Pango::ALIGN_LEFT);
+ cr->set_source_rgba(1.0, 1.0, 1.0, 1.0);
+ int width, height;
+ layout->get_pixel_size(width, height);
+ cr->move_to(
+ background_area.get_x() + 1,
+ cell_area.get_y() + cell_area.get_height() / 2.0 - height / 2.0);
+ layout->show_in_cairo_context(cr);
+
+ // expander
+ constexpr static int len = 5;
+ constexpr static int offset = 24;
+ int x1, y1, x2, y2, x3, y3;
+ if (property_expanded()) {
+ x1 = background_area.get_x() + offset;
+ y1 = background_area.get_y() + background_area.get_height() / 2 - len;
+ x2 = background_area.get_x() + offset + len;
+ y2 = background_area.get_y() + background_area.get_height() / 2 + len;
+ x3 = background_area.get_x() + offset + len * 2;
+ y3 = background_area.get_y() + background_area.get_height() / 2 - len;
+ } else {
+ x1 = background_area.get_x() + offset;
+ y1 = background_area.get_y() + background_area.get_height() / 2 - len;
+ x2 = background_area.get_x() + offset + len * 2;
+ y2 = background_area.get_y() + background_area.get_height() / 2;
+ x3 = background_area.get_x() + offset;
+ y3 = background_area.get_y() + background_area.get_height() / 2 + len;
+ }
+ cr->move_to(x1, y1);
+ cr->line_to(x2, y2);
+ cr->line_to(x3, y3);
+ const auto expander_color = Gdk::RGBA(Abaddon::Get().GetSettings().ChannelsExpanderColor);
+ cr->set_source_rgb(expander_color.get_red(), expander_color.get_green(), expander_color.get_blue());
+ cr->stroke();
}
// voice participant
@@ -659,18 +699,40 @@ void CellRendererChannels::get_preferred_height_for_width_vfunc_voice_participan
}
void CellRendererChannels::render_vfunc_voice_participant(const Cairo::RefPtr<Cairo::Context> &cr, Gtk::Widget &widget, const Gdk::Rectangle &background_area, const Gdk::Rectangle &cell_area, Gtk::CellRendererState flags) {
- Gtk::Requisition minimum_size, natural_size;
- m_renderer_text.get_preferred_size(widget, minimum_size, natural_size);
+ Gtk::Requisition text_minimum, text_natural;
+ m_renderer_text.get_preferred_size(widget, text_minimum, text_natural);
- const int text_x = background_area.get_x() + 27;
- const int text_y = background_area.get_y() + background_area.get_height() / 2 - natural_size.height / 2;
- const int text_w = natural_size.width;
- const int text_h = natural_size.height;
+ Gtk::Requisition minimum, natural;
+ get_preferred_size(widget, minimum, natural);
+
+ int pixbuf_w = 0;
+ int pixbuf_h = 0;
+
+ if (auto pixbuf = m_property_pixbuf.get_value()) {
+ pixbuf_w = pixbuf->get_width();
+ pixbuf_h = pixbuf->get_height();
+ }
+
+ const double icon_w = pixbuf_w;
+ const double icon_h = pixbuf_h;
+ const double icon_x = background_area.get_x() + 28;
+ const double icon_y = background_area.get_y() + background_area.get_height() / 2.0 - icon_h / 2.0;
+
+ const double text_x = icon_x + icon_w + 5.0;
+ const double text_y = background_area.get_y() + background_area.get_height() / 2.0 - text_natural.height / 2.0;
+ const double text_w = text_natural.width;
+ const double text_h = text_natural.height;
Gdk::Rectangle text_cell_area(text_x, text_y, text_w, text_h);
- m_renderer_text.property_foreground_rgba() = Gdk::RGBA("#f00");
+ m_renderer_text.property_scale() = Pango::SCALE_SMALL;
m_renderer_text.render(cr, widget, background_area, text_cell_area, flags);
- m_renderer_text.property_foreground_set() = false;
+ m_renderer_text.property_scale_set() = false;
+
+ 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();
+ }
}
#endif