diff options
author | ouwou <26526779+ouwou@users.noreply.github.com> | 2020-11-10 01:38:44 -0500 |
---|---|---|
committer | ouwou <26526779+ouwou@users.noreply.github.com> | 2020-11-10 01:38:44 -0500 |
commit | eb0feef51166eeabd58993c484e85e0739285aa1 (patch) | |
tree | 200c93680df8ecbcf127cc59e2f940e9f8af4b90 /components | |
parent | 823e1786e016a0dce58ffda0506608f2a2fce932 (diff) | |
download | abaddon-portaudio-eb0feef51166eeabd58993c484e85e0739285aa1.tar.gz abaddon-portaudio-eb0feef51166eeabd58993c484e85e0739285aa1.zip |
use textviews in channel list + parse emojis
Diffstat (limited to 'components')
-rw-r--r-- | components/channels.cpp | 98 | ||||
-rw-r--r-- | components/channels.hpp | 15 | ||||
-rw-r--r-- | components/chatmessage.cpp | 33 | ||||
-rw-r--r-- | components/chatwindow.cpp | 2 |
4 files changed, 100 insertions, 48 deletions
diff --git a/components/channels.cpp b/components/channels.cpp index adcfe13..8516f94 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -9,6 +9,24 @@ void ChannelListRow::Collapse() {} void ChannelListRow::Expand() {} +void ChannelListRow::MakeReadOnly(Gtk::TextView *tv) { + tv->set_can_focus(false); + tv->set_editable(false); + tv->signal_realize().connect([tv]() { + auto window = tv->get_window(Gtk::TEXT_WINDOW_TEXT); + auto display = window->get_display(); + auto cursor = Gdk::Cursor::create(display, "default"); // textview uses "text" which looks out of place + window->set_cursor(cursor); + }); + // stupid hack to prevent selection + auto buf = tv->get_buffer(); + buf->property_has_selection().signal_changed().connect([tv, buf]() { + Gtk::TextBuffer::iterator a, b; + buf->get_bounds(a, b); + buf->select_range(a, a); + }); +} + ChannelListRowDMHeader::ChannelListRowDMHeader() { m_ev = Gtk::manage(new Gtk::EventBox); m_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL)); @@ -31,7 +49,8 @@ ChannelListRowDMChannel::ChannelListRowDMChannel(const Channel *data) { ID = data->ID; m_ev = Gtk::manage(new Gtk::EventBox); m_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL)); - m_lbl = Gtk::manage(new Gtk::Label); + m_lbl = Gtk::manage(new Gtk::TextView); + MakeReadOnly(m_lbl); get_style_context()->add_class("channel-row"); m_lbl->get_style_context()->add_class("channel-row-label"); @@ -50,10 +69,12 @@ ChannelListRowDMChannel::ChannelListRowDMChannel(const Channel *data) { } } + auto buf = m_lbl->get_buffer(); if (data->Type == ChannelType::DM) - m_lbl->set_text(data->Recipients[0].Username); + buf->set_text(data->Recipients[0].Username); else if (data->Type == ChannelType::GROUP_DM) - m_lbl->set_text(std::to_string(data->Recipients.size()) + " users"); + buf->set_text(std::to_string(data->Recipients.size()) + " users"); + Abaddon::Get().GetEmojis().ReplaceEmojis(buf, ChannelEmojiSize); m_box->set_halign(Gtk::ALIGN_START); if (m_icon != nullptr) @@ -73,7 +94,8 @@ ChannelListRowGuild::ChannelListRowGuild(const Guild *data) { ID = data->ID; m_ev = Gtk::manage(new Gtk::EventBox); m_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL)); - m_lbl = Gtk::manage(new Gtk::Label); + m_lbl = Gtk::manage(new Gtk::TextView); + MakeReadOnly(m_lbl); if (data->HasIcon()) { auto buf = Abaddon::Get().GetImageManager().GetFromURLIfCached(data->GetIconURL("png", "32")); @@ -91,7 +113,11 @@ ChannelListRowGuild::ChannelListRowGuild(const Guild *data) { get_style_context()->add_class("channel-row-guild"); m_lbl->get_style_context()->add_class("channel-row-label"); - m_lbl->set_markup("<b>" + Glib::Markup::escape_text(data->Name) + "</b>"); + auto buf = m_lbl->get_buffer(); + Gtk::TextBuffer::iterator start, end; + buf->get_bounds(start, end); + buf->insert_markup(start, "<b>" + Glib::Markup::escape_text(data->Name) + "</b>"); + Abaddon::Get().GetEmojis().ReplaceEmojis(buf, ChannelEmojiSize); m_box->set_halign(Gtk::ALIGN_START); m_box->pack_start(*m_icon); m_box->pack_start(*m_lbl); @@ -108,14 +134,17 @@ ChannelListRowCategory::ChannelListRowCategory(const Channel *data) { ID = data->ID; m_ev = Gtk::manage(new Gtk::EventBox); m_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL)); - m_lbl = Gtk::manage(new Gtk::Label); + m_lbl = Gtk::manage(new Gtk::TextView); + MakeReadOnly(m_lbl); m_arrow = Gtk::manage(new Gtk::Arrow(Gtk::ARROW_DOWN, Gtk::SHADOW_NONE)); get_style_context()->add_class("channel-row"); get_style_context()->add_class("channel-row-category"); m_lbl->get_style_context()->add_class("channel-row-label"); - m_lbl->set_text(data->Name); + auto buf = m_lbl->get_buffer(); + buf->set_text(data->Name); + Abaddon::Get().GetEmojis().ReplaceEmojis(buf, ChannelEmojiSize); m_box->set_halign(Gtk::ALIGN_START); m_box->pack_start(*m_arrow); m_box->pack_start(*m_lbl); @@ -136,13 +165,16 @@ ChannelListRowChannel::ChannelListRowChannel(const Channel *data) { ID = data->ID; m_ev = Gtk::manage(new Gtk::EventBox); m_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL)); - m_lbl = Gtk::manage(new Gtk::Label); + m_lbl = Gtk::manage(new Gtk::TextView); + MakeReadOnly(m_lbl); get_style_context()->add_class("channel-row"); get_style_context()->add_class("channel-row-channel"); m_lbl->get_style_context()->add_class("channel-row-label"); - m_lbl->set_text("#" + data->Name); + auto buf = m_lbl->get_buffer(); + buf->set_text("#" + data->Name); + Abaddon::Get().GetEmojis().ReplaceEmojis(buf, ChannelEmojiSize); m_box->set_halign(Gtk::ALIGN_START); m_box->pack_start(*m_lbl); m_ev->add(*m_box); @@ -189,6 +221,18 @@ ChannelList::ChannelList() { m_main->show_all(); m_update_dispatcher.connect(sigc::mem_fun(*this, &ChannelList::UpdateListingInternal)); + + // maybe will regret doing it this way + auto &discord = Abaddon::Get().GetDiscordClient(); + discord.signal_message_create().connect(sigc::track_obj([this, &discord](Snowflake message_id) { + const auto *message = discord.GetMessage(message_id); + const auto *channel = discord.GetChannel(message->ChannelID); + if (channel == nullptr) return; + if (channel->Type == ChannelType::DM || channel->Type == ChannelType::GROUP_DM) + CheckBumpDM(message->ChannelID); + // clang-format off + }, this)); + // clang-format on } Gtk::Widget *ChannelList::GetRoot() const { @@ -462,6 +506,7 @@ void ChannelList::DeleteRow(ChannelListRow *row) { m_id_to_row.erase(row->ID); delete row; } + void ChannelList::on_row_activated(Gtk::ListBoxRow *tmprow) { auto row = dynamic_cast<ChannelListRow *>(tmprow); if (row == nullptr) return; @@ -556,7 +601,14 @@ void ChannelList::InsertGuildAt(Snowflake id, int pos) { } void ChannelList::AddPrivateChannels() { - auto dms = Abaddon::Get().GetDiscordClient().GetPrivateChannels(); + auto dms_ = Abaddon::Get().GetDiscordClient().GetPrivateChannels(); + std::vector<const Channel *> dms; + const auto &discord = Abaddon::Get().GetDiscordClient(); + for (const auto &x : dms_) + dms.push_back(discord.GetChannel(x)); + std::sort(dms.begin(), dms.end(), [&](const Channel *a, const Channel *b) -> bool { + return a->LastMessageID > b->LastMessageID; + }); m_dm_header_row = Gtk::manage(new ChannelListRowDMHeader); m_dm_header_row->show_all(); @@ -564,7 +616,9 @@ void ChannelList::AddPrivateChannels() { m_list->add(*m_dm_header_row); for (const auto &dm : dms) { - auto *dm_row = Gtk::manage(new ChannelListRowDMChannel(Abaddon::Get().GetDiscordClient().GetChannel(dm))); + auto *dm_row = Gtk::manage(new ChannelListRowDMChannel(dm)); + dm_row->Parent = m_dm_header_row; + m_dm_id_to_row[dm->ID] = dm_row; dm_row->IsUserCollapsed = false; m_list->add(*dm_row); m_dm_header_row->Children.insert(dm_row); @@ -660,6 +714,28 @@ void ChannelList::AttachChannelMenuHandler(Gtk::ListBoxRow *row) { }); } +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; + auto *row = it->second; + const auto index = row->get_index(); + if (index == 1) return; // 1 is top of dm list + const bool selected = row->is_selected(); + row->Parent->Children.erase(row); + delete row; + auto *dm_row = Gtk::manage(new ChannelListRowDMChannel(Abaddon::Get().GetDiscordClient().GetChannel(channel_id))); + dm_row->Parent = m_dm_header_row; + m_dm_header_row->Children.insert(dm_row); + m_dm_id_to_row[channel_id] = dm_row; + dm_row->IsUserCollapsed = false; + m_list->insert(*dm_row, 1); + m_dm_header_row->Children.insert(dm_row); + if (selected) + m_list->select_row(*dm_row); + if (m_dm_header_row->is_visible() && !m_dm_header_row->IsUserCollapsed) + dm_row->show(); +} + ChannelList::type_signal_action_channel_item_select ChannelList::signal_action_channel_item_select() { return m_signal_action_channel_item_select; } diff --git a/components/channels.hpp b/components/channels.hpp index 0326841..485cb5f 100644 --- a/components/channels.hpp +++ b/components/channels.hpp @@ -8,6 +8,8 @@ #include <sigc++/sigc++.h> #include "../discord/discord.hpp" +static const constexpr int ChannelEmojiSize = 16; + class ChannelListRow : public Gtk::ListBoxRow { public: bool IsUserCollapsed; @@ -17,6 +19,8 @@ public: virtual void Collapse(); virtual void Expand(); + + static void MakeReadOnly(Gtk::TextView *tv); }; class ChannelListRowDMHeader : public ChannelListRow { @@ -38,7 +42,7 @@ protected: Gtk::EventBox *m_ev; Gtk::Box *m_box; - Gtk::Label *m_lbl; + Gtk::TextView *m_lbl; Gtk::Image *m_icon = nullptr; }; @@ -53,7 +57,7 @@ protected: Gtk::EventBox *m_ev; Gtk::Box *m_box; - Gtk::Label *m_lbl; + Gtk::TextView *m_lbl; Gtk::Image *m_icon; }; @@ -67,7 +71,7 @@ public: protected: Gtk::EventBox *m_ev; Gtk::Box *m_box; - Gtk::Label *m_lbl; + Gtk::TextView *m_lbl; Gtk::Arrow *m_arrow; }; @@ -78,7 +82,7 @@ public: protected: Gtk::EventBox *m_ev; Gtk::Box *m_box; - Gtk::Label *m_lbl; + Gtk::TextView *m_lbl; }; class ChannelList { @@ -133,6 +137,7 @@ protected: // i would use one map but in really old guilds there can be a channel w/ same id as the guild so this hacky shit has to do std::unordered_map<Snowflake, ChannelListRow *> m_guild_id_to_row; std::unordered_map<Snowflake, ChannelListRow *> m_id_to_row; + std::unordered_map<Snowflake, ChannelListRow *> m_dm_id_to_row; void InsertGuildAt(Snowflake id, int pos); @@ -141,6 +146,8 @@ protected: void AttachGuildMenuHandler(Gtk::ListBoxRow *row); void AttachChannelMenuHandler(Gtk::ListBoxRow *row); + void CheckBumpDM(Snowflake channel_id); + public: typedef sigc::signal<void, Snowflake> type_signal_action_channel_item_select; typedef sigc::signal<void, Snowflake> type_signal_action_guild_move_up; diff --git a/components/chatmessage.cpp b/components/chatmessage.cpp index f528e37..a36b67f 100644 --- a/components/chatmessage.cpp +++ b/components/chatmessage.cpp @@ -451,38 +451,7 @@ void ChatMessageItemContainer::HandleUserMentions(Gtk::TextView *tv) { } void ChatMessageItemContainer::HandleStockEmojis(Gtk::TextView *tv) { - auto buf = tv->get_buffer(); - auto text = GetText(buf); - - auto &emojis = Abaddon::Get().GetEmojis(); - int searchpos; - for (const auto &pattern : emojis.GetPatterns()) { - searchpos = 0; - Glib::RefPtr<Gdk::Pixbuf> pixbuf; - while (true) { - size_t r = text.find(pattern, searchpos); - if (r == Glib::ustring::npos) break; - if (!pixbuf) { - pixbuf = emojis.GetPixBuf(pattern); - if (pixbuf) - pixbuf = pixbuf->scale_simple(24, 24, Gdk::INTERP_BILINEAR); - else - break; - } - searchpos = r + pattern.size(); - - const auto start_it = buf->get_iter_at_offset(r); - const auto end_it = buf->get_iter_at_offset(r + pattern.size()); - - auto it = buf->erase(start_it, end_it); - buf->insert_pixbuf(it, pixbuf); - - int alen = text.size(); - text = GetText(buf); - int blen = text.size(); - searchpos -= (alen - blen); - } - } + Abaddon::Get().GetEmojis().ReplaceEmojis(tv->get_buffer()); } void ChatMessageItemContainer::HandleCustomEmojis(Gtk::TextView *tv) { diff --git a/components/chatwindow.cpp b/components/chatwindow.cpp index d447177..6d7edca 100644 --- a/components/chatwindow.cpp +++ b/components/chatwindow.cpp @@ -49,7 +49,7 @@ ChatWindow::ChatWindow() { m_input->set_halign(Gtk::ALIGN_FILL); m_input->set_wrap_mode(Gtk::WRAP_WORD_CHAR); - m_input_scroll->set_max_content_height(170); + m_input_scroll->set_max_content_height(200); m_input_scroll->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); m_input_scroll->add(*m_input); |