diff options
author | ouwou <26526779+ouwou@users.noreply.github.com> | 2023-05-14 23:55:38 -0400 |
---|---|---|
committer | ouwou <26526779+ouwou@users.noreply.github.com> | 2023-05-14 23:55:38 -0400 |
commit | d0fa9cc289d8398a27ddf2a66783b5d460e2210a (patch) | |
tree | ad98161438282800927556cba438e8ded6fbbed2 /src/components | |
parent | 49f6cd021beb70a2f9e8c359275af69922bffb83 (diff) | |
download | abaddon-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.cpp | 61 | ||||
-rw-r--r-- | src/components/channels.hpp | 2 | ||||
-rw-r--r-- | src/components/channelscellrenderer.cpp | 84 |
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 |