From 3e0cd83dd6026dc701c548dc40b41f5accbc29db Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Mon, 16 Oct 2023 21:31:28 -0400 Subject: [PATCH] start channel list refactor for server list --- .../cellrendererchannels.cpp} | 2 +- .../cellrendererchannels.hpp} | 0 .../channellist.cpp} | 91 ++++++------------- .../channellist.hpp} | 6 +- .../channellist/classic/guildlist.cpp | 23 +++++ .../channellist/classic/guildlist.hpp | 12 +++ .../classic/guildlistfolderitem.cpp | 18 ++++ .../classic/guildlistfolderitem.hpp | 18 ++++ .../classic/guildlistguilditem.cpp | 29 ++++++ .../classic/guildlistguilditem.hpp | 17 ++++ src/windows/mainwindow.cpp | 1 + src/windows/mainwindow.hpp | 2 +- 12 files changed, 152 insertions(+), 67 deletions(-) rename src/components/{channelscellrenderer.cpp => channellist/cellrendererchannels.cpp} (99%) rename src/components/{channelscellrenderer.hpp => channellist/cellrendererchannels.hpp} (100%) rename src/components/{channels.cpp => channellist/channellist.cpp} (95%) rename src/components/{channels.hpp => channellist/channellist.hpp} (97%) create mode 100644 src/components/channellist/classic/guildlist.cpp create mode 100644 src/components/channellist/classic/guildlist.hpp create mode 100644 src/components/channellist/classic/guildlistfolderitem.cpp create mode 100644 src/components/channellist/classic/guildlistfolderitem.hpp create mode 100644 src/components/channellist/classic/guildlistguilditem.cpp create mode 100644 src/components/channellist/classic/guildlistguilditem.hpp diff --git a/src/components/channelscellrenderer.cpp b/src/components/channellist/cellrendererchannels.cpp similarity index 99% rename from src/components/channelscellrenderer.cpp rename to src/components/channellist/cellrendererchannels.cpp index ac98512..e0079cd 100644 --- a/src/components/channelscellrenderer.cpp +++ b/src/components/channellist/cellrendererchannels.cpp @@ -1,4 +1,4 @@ -#include "channelscellrenderer.hpp" +#include "cellrendererchannels.hpp" constexpr static int MentionsRightPad = 7; #ifndef M_PI diff --git a/src/components/channelscellrenderer.hpp b/src/components/channellist/cellrendererchannels.hpp similarity index 100% rename from src/components/channelscellrenderer.hpp rename to src/components/channellist/cellrendererchannels.hpp diff --git a/src/components/channels.cpp b/src/components/channellist/channellist.cpp similarity index 95% rename from src/components/channels.cpp rename to src/components/channellist/channellist.cpp index 9fd4abd..51e8f33 100644 --- a/src/components/channels.cpp +++ b/src/components/channellist/channellist.cpp @@ -1,6 +1,6 @@ -#include "channels.hpp" +#include "channellist.hpp" #include "imgmanager.hpp" -#include "statusindicator.hpp" +#include "components/statusindicator.hpp" #include #include #include @@ -8,6 +8,7 @@ ChannelList::ChannelList() : Glib::ObjectBase(typeid(ChannelList)) , m_model(Gtk::TreeStore::create(m_columns)) + , m_filter_model(Gtk::TreeModelFilter::create(m_model)) , m_menu_guild_copy_id("_Copy ID", true) , m_menu_guild_settings("View _Settings", true) , m_menu_guild_leave("_Leave", true) @@ -36,9 +37,9 @@ ChannelList::ChannelList() , m_menu_thread_mark_as_read("Mark as _Read", true) { get_style_context()->add_class("channel-list"); - // todo: move to method + // Filter iters const auto cb = [this](const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *column) { - auto row = *m_model->get_iter(path); + auto row = *m_filter_model->get_iter(path); 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 @@ -72,13 +73,22 @@ ChannelList::ChannelList() m_view.set_show_expanders(false); m_view.set_enable_search(false); m_view.set_headers_visible(false); - m_view.set_model(m_model); + m_view.set_model(m_filter_model); m_model->set_sort_column(m_columns.m_sort, Gtk::SORT_ASCENDING); m_model->signal_row_inserted().connect([this](const Gtk::TreeModel::Path &path, const Gtk::TreeModel::iterator &iter) { if (m_updating_listing) return; - if (auto parent = iter->parent(); parent && (*parent)[m_columns.m_expanded]) - m_view.expand_row(m_model->get_path(parent), false); + if (auto parent = iter->parent(); parent && (*parent)[m_columns.m_expanded]) { + const auto filter_path = m_filter_model->convert_child_path_to_path(m_model->get_path(parent)); + m_view.expand_row(filter_path, false); + } + }); + + m_filter_model->set_visible_func([this](const Gtk::TreeModel::const_iterator &iter) -> bool { + if ((*iter)[m_columns.m_type] == RenderType::Guild) { + return (*iter)[m_columns.m_id] == 754921263616753776ULL; + } + return true; }); m_view.show(); @@ -594,9 +604,9 @@ void ChannelList::SetActiveChannel(Snowflake id, bool expand_to) { const auto channel_iter = GetIteratorForRowFromID(id); if (channel_iter) { if (expand_to) { - m_view.expand_to_path(m_model->get_path(channel_iter)); + m_view.expand_to_path(m_filter_model->convert_child_path_to_path(m_model->get_path(channel_iter))); } - m_view.get_selection()->select(channel_iter); + m_view.get_selection()->select(m_filter_model->convert_child_iter_to_iter(channel_iter)); } else { m_view.get_selection()->unselect_all(); const auto channel = Abaddon::Get().GetDiscordClient().GetChannel(id); @@ -604,64 +614,17 @@ void ChannelList::SetActiveChannel(Snowflake id, bool expand_to) { auto parent_iter = GetIteratorForRowFromID(*channel->ParentID); if (!parent_iter) return; m_temporary_thread_row = CreateThreadRow(parent_iter->children(), *channel); - m_view.get_selection()->select(m_temporary_thread_row); + m_view.get_selection()->select(m_filter_model->convert_child_iter_to_iter(m_temporary_thread_row)); } } void ChannelList::UseExpansionState(const ExpansionStateRoot &root) { - auto recurse = [this](auto &self, const ExpansionStateRoot &root) -> void { - for (const auto &[id, state] : root.Children) { - Gtk::TreeModel::iterator row_iter; - if (const auto map_iter = m_tmp_row_map.find(id); map_iter != m_tmp_row_map.end()) { - row_iter = map_iter->second; - } else if (const auto map_iter = m_tmp_guild_row_map.find(id); map_iter != m_tmp_guild_row_map.end()) { - row_iter = map_iter->second; - } - - if (row_iter) { - if (state.IsExpanded) - m_view.expand_row(m_model->get_path(row_iter), false); - else - m_view.collapse_row(m_model->get_path(row_iter)); - } - - self(self, state.Children); - } - }; - - for (const auto &[id, state] : root.Children) { - if (const auto iter = GetIteratorForTopLevelFromID(id)) { - if (state.IsExpanded) - m_view.expand_row(m_model->get_path(iter), false); - else - m_view.collapse_row(m_model->get_path(iter)); - } - - recurse(recurse, state.Children); - } - m_tmp_row_map.clear(); } ExpansionStateRoot ChannelList::GetExpansionState() const { ExpansionStateRoot r; - auto recurse = [this](auto &self, const Gtk::TreeRow &row) -> ExpansionState { - ExpansionState r; - - r.IsExpanded = row[m_columns.m_expanded]; - for (const auto &child : row.children()) - r.Children.Children[static_cast(child[m_columns.m_id])] = self(self, child); - - return r; - }; - - for (const auto &child : m_model->children()) { - const auto id = static_cast(child[m_columns.m_id]); - if (static_cast(id) == 0ULL) continue; // dont save DM header - r.Children[id] = recurse(recurse, child); - } - return r; } @@ -969,7 +932,7 @@ void ChannelList::OnRowExpanded(const Gtk::TreeModel::iterator &iter, const Gtk: // restore previous expansion for (auto it = iter->children().begin(); it != iter->children().end(); it++) { if ((*it)[m_columns.m_expanded]) - m_view.expand_row(m_model->get_path(it), false); + m_view.expand_row(m_filter_model->get_path(it), false); } // try and restore selection if previous collapsed @@ -981,11 +944,13 @@ void ChannelList::OnRowExpanded(const Gtk::TreeModel::iterator &iter, const Gtk: } bool ChannelList::SelectionFunc(const Glib::RefPtr &model, const Gtk::TreeModel::Path &path, bool is_currently_selected) { - if (auto selection = m_view.get_selection()) - if (auto row = selection->get_selected()) - m_last_selected = m_model->get_path(row); + if (auto selection = m_view.get_selection()) { + if (auto row = selection->get_selected()) { + m_last_selected = m_filter_model->get_path(row); + } + } - auto type = (*m_model->get_iter(path))[m_columns.m_type]; + auto type = (*model->get_iter(path))[m_columns.m_type]; return type == RenderType::TextChannel || type == RenderType::DM || type == RenderType::Thread; } @@ -1139,7 +1104,7 @@ void ChannelList::OnMessageCreate(const Message &msg) { bool ChannelList::OnButtonPressEvent(GdkEventButton *ev) { if (ev->button == GDK_BUTTON_SECONDARY && ev->type == GDK_BUTTON_PRESS) { if (m_view.get_path_at_pos(static_cast(ev->x), static_cast(ev->y), m_path_for_menu)) { - auto row = (*m_model->get_iter(m_path_for_menu)); + auto row = (*m_filter_model->get_iter(m_path_for_menu)); switch (static_cast(row[m_columns.m_type])) { case RenderType::Guild: OnGuildSubmenuPopup(); diff --git a/src/components/channels.hpp b/src/components/channellist/channellist.hpp similarity index 97% rename from src/components/channels.hpp rename to src/components/channellist/channellist.hpp index 9d449e4..df7dbac 100644 --- a/src/components/channels.hpp +++ b/src/components/channellist/channellist.hpp @@ -8,11 +8,12 @@ #include #include #include +#include #include #include #include "discord/discord.hpp" #include "state.hpp" -#include "channelscellrenderer.hpp" +#include "cellrendererchannels.hpp" constexpr static int GuildIconSize = 24; constexpr static int DMIconSize = 20; @@ -82,6 +83,7 @@ protected: ModelColumns m_columns; Glib::RefPtr m_model; + Glib::RefPtr m_filter_model; Gtk::TreeModel::iterator AddFolder(const UserSettingsGuildFoldersEntry &folder); Gtk::TreeModel::iterator AddGuild(const GuildData &guild, const Gtk::TreeNodeChildren &root); @@ -116,7 +118,7 @@ protected: void UpdateCreateDMChannel(const ChannelData &channel); void SetDMChannelIcon(Gtk::TreeIter iter, const ChannelData &dm); - void RedrawUnreadIndicatorsForChannel(const ChannelData& channel); + void RedrawUnreadIndicatorsForChannel(const ChannelData &channel); void OnMessageAck(const MessageAckData &data); void OnMessageCreate(const Message &msg); diff --git a/src/components/channellist/classic/guildlist.cpp b/src/components/channellist/classic/guildlist.cpp new file mode 100644 index 0000000..0d5737b --- /dev/null +++ b/src/components/channellist/classic/guildlist.cpp @@ -0,0 +1,23 @@ +#include "guildlist.hpp" +#include "guildlistfolderitem.hpp" + +GuildList::GuildList() { + set_selection_mode(Gtk::SELECTION_NONE); + show_all_children(); +} + +void GuildList::AddGuild(Snowflake id) { + const auto guild = Abaddon::Get().GetDiscordClient().GetGuild(id); + if (!guild.has_value()) return; + + auto *item = Gtk::make_managed(*guild); + item->show(); + add(*item); +} + +void GuildList::Clear() { + const auto children = get_children(); + for (auto child : children) { + delete child; + } +} diff --git a/src/components/channellist/classic/guildlist.hpp b/src/components/channellist/classic/guildlist.hpp new file mode 100644 index 0000000..244313f --- /dev/null +++ b/src/components/channellist/classic/guildlist.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "discord/snowflake.hpp" + +class GuildList : public Gtk::ListBox { +public: + GuildList(); + + void AddGuild(Snowflake id); + + void Clear(); +}; diff --git a/src/components/channellist/classic/guildlistfolderitem.cpp b/src/components/channellist/classic/guildlistfolderitem.cpp new file mode 100644 index 0000000..36d5a5a --- /dev/null +++ b/src/components/channellist/classic/guildlistfolderitem.cpp @@ -0,0 +1,18 @@ +#include "guildlistfolderitem.hpp" + +GuildListFolderItem::GuildListFolderItem() { + m_revealer.add(m_box); + m_revealer.set_reveal_child(true); + + m_ev.signal_button_press_event().connect([this](GdkEventButton *event) -> bool { + if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY) { + m_revealer.set_reveal_child(!m_revealer.get_reveal_child()); + } + return false; + }); + + m_ev.add(m_image); + add(m_ev); + add(m_revealer); + show_all_children(); +} diff --git a/src/components/channellist/classic/guildlistfolderitem.hpp b/src/components/channellist/classic/guildlistfolderitem.hpp new file mode 100644 index 0000000..3506969 --- /dev/null +++ b/src/components/channellist/classic/guildlistfolderitem.hpp @@ -0,0 +1,18 @@ +#pragma once +#include +#include +#include +#include + +#include "guildlistguilditem.hpp" + +class GuildListFolderItem : public Gtk::VBox { +public: + GuildListFolderItem(); + +private: + Gtk::EventBox m_ev; + Gtk::Image m_image; + Gtk::Revealer m_revealer; + Gtk::VBox m_box; +}; diff --git a/src/components/channellist/classic/guildlistguilditem.cpp b/src/components/channellist/classic/guildlistguilditem.cpp new file mode 100644 index 0000000..88ed2a9 --- /dev/null +++ b/src/components/channellist/classic/guildlistguilditem.cpp @@ -0,0 +1,29 @@ +#include "guildlistguilditem.hpp" + +GuildListGuildItem::GuildListGuildItem(const GuildData &guild) + : ID(guild.ID) { + m_image.property_pixbuf() = Abaddon::Get().GetImageManager().GetPlaceholder(48); + add(m_image); + show_all_children(); + + signal_button_press_event().connect([this](GdkEventButton *event) -> bool { + if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY) { + printf("Click %llu\n", (uint64_t)ID); + } + return true; + }); + + set_tooltip_text(guild.Name); + + UpdateIcon(); +} + +void GuildListGuildItem::UpdateIcon() { + const auto guild = Abaddon::Get().GetDiscordClient().GetGuild(ID); + if (!guild.has_value()) return; + Abaddon::Get().GetImageManager().LoadFromURL(guild->GetIconURL("png", "64"), sigc::mem_fun(*this, &GuildListGuildItem::OnIconFetched)); +} + +void GuildListGuildItem::OnIconFetched(const Glib::RefPtr &pb) { + m_image.property_pixbuf() = pb->scale_simple(48, 48, Gdk::INTERP_BILINEAR); +} diff --git a/src/components/channellist/classic/guildlistguilditem.hpp b/src/components/channellist/classic/guildlistguilditem.hpp new file mode 100644 index 0000000..3114a05 --- /dev/null +++ b/src/components/channellist/classic/guildlistguilditem.hpp @@ -0,0 +1,17 @@ +#pragma once +#include +#include +#include "discord/guild.hpp" + +class GuildListGuildItem : public Gtk::EventBox { +public: + GuildListGuildItem(const GuildData &guild); + + Snowflake ID; + +private: + void UpdateIcon(); + void OnIconFetched(const Glib::RefPtr &pb); + + Gtk::Image m_image; +}; diff --git a/src/windows/mainwindow.cpp b/src/windows/mainwindow.cpp index 8e030ed..8156659 100644 --- a/src/windows/mainwindow.cpp +++ b/src/windows/mainwindow.cpp @@ -1,4 +1,5 @@ #include "mainwindow.hpp" +#include "components/channellist/channellist.hpp" MainWindow::MainWindow() : m_main_box(Gtk::ORIENTATION_VERTICAL) diff --git a/src/windows/mainwindow.hpp b/src/windows/mainwindow.hpp index ce2e636..37c1b87 100644 --- a/src/windows/mainwindow.hpp +++ b/src/windows/mainwindow.hpp @@ -1,5 +1,5 @@ #pragma once -#include "components/channels.hpp" +#include "components/channellist/channellist.hpp" #include "components/chatwindow.hpp" #include "components/memberlist.hpp" #include "components/friendslist.hpp"