start new member list
This commit is contained in:
parent
67b23abbd4
commit
1056596dfc
112
src/components/cellrenderermemberlist.cpp
Normal file
112
src/components/cellrenderermemberlist.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
#include "cellrenderermemberlist.hpp"
|
||||
|
||||
CellRendererMemberList::CellRendererMemberList()
|
||||
: Glib::ObjectBase(typeid(CellRendererMemberList))
|
||||
, Gtk::CellRenderer()
|
||||
, m_property_type(*this, "render-type")
|
||||
, m_property_id(*this, "id")
|
||||
, m_property_name(*this, "name") {
|
||||
property_mode() = Gtk::CELL_RENDERER_MODE_ACTIVATABLE;
|
||||
property_xpad() = 2;
|
||||
property_ypad() = 2;
|
||||
m_property_name.get_proxy().signal_changed().connect([this]() {
|
||||
m_renderer_text.property_markup() = m_property_name;
|
||||
});
|
||||
}
|
||||
|
||||
Glib::PropertyProxy<MemberListRenderType> CellRendererMemberList::property_type() {
|
||||
return m_property_type.get_proxy();
|
||||
}
|
||||
|
||||
Glib::PropertyProxy<uint64_t> CellRendererMemberList::property_id() {
|
||||
return m_property_id.get_proxy();
|
||||
}
|
||||
|
||||
Glib::PropertyProxy<Glib::ustring> CellRendererMemberList::property_name() {
|
||||
return m_property_name.get_proxy();
|
||||
}
|
||||
|
||||
void CellRendererMemberList::get_preferred_width_vfunc(Gtk::Widget &widget, int &minimum_width, int &natural_width) const {
|
||||
switch (m_property_type.get_value()) {
|
||||
case MemberListRenderType::Role:
|
||||
return get_preferred_width_vfunc_role(widget, minimum_width, natural_width);
|
||||
case MemberListRenderType::Member:
|
||||
return get_preferred_width_vfunc_member(widget, minimum_width, natural_width);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRendererMemberList::get_preferred_width_for_height_vfunc(Gtk::Widget &widget, int height, int &minimum_width, int &natural_width) const {
|
||||
switch (m_property_type.get_value()) {
|
||||
case MemberListRenderType::Role:
|
||||
return get_preferred_width_for_height_vfunc_role(widget, height, minimum_width, natural_width);
|
||||
case MemberListRenderType::Member:
|
||||
return get_preferred_width_for_height_vfunc_member(widget, height, minimum_width, natural_width);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRendererMemberList::get_preferred_height_vfunc(Gtk::Widget &widget, int &minimum_width, int &natural_width) const {
|
||||
switch (m_property_type.get_value()) {
|
||||
case MemberListRenderType::Role:
|
||||
return get_preferred_height_vfunc_role(widget, minimum_width, natural_width);
|
||||
case MemberListRenderType::Member:
|
||||
return get_preferred_height_vfunc_member(widget, minimum_width, natural_width);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRendererMemberList::get_preferred_height_for_width_vfunc(Gtk::Widget &widget, int width, int &minimum_height, int &natural_height) const {
|
||||
switch (m_property_type.get_value()) {
|
||||
case MemberListRenderType::Role:
|
||||
return get_preferred_height_for_width_vfunc_role(widget, width, minimum_height, natural_height);
|
||||
case MemberListRenderType::Member:
|
||||
return get_preferred_height_for_width_vfunc_member(widget, width, minimum_height, natural_height);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRendererMemberList::render_vfunc(const Cairo::RefPtr<Cairo::Context> &cr, Gtk::Widget &widget, const Gdk::Rectangle &background_area, const Gdk::Rectangle &cell_area, Gtk::CellRendererState flags) {
|
||||
switch (m_property_type.get_value()) {
|
||||
case MemberListRenderType::Role:
|
||||
return render_vfunc_role(cr, widget, background_area, cell_area, flags);
|
||||
case MemberListRenderType::Member:
|
||||
return render_vfunc_member(cr, widget, background_area, cell_area, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRendererMemberList::get_preferred_width_vfunc_role(Gtk::Widget &widget, int &minimum_width, int &natural_width) const {
|
||||
m_renderer_text.get_preferred_width(widget, minimum_width, natural_width);
|
||||
}
|
||||
|
||||
void CellRendererMemberList::get_preferred_width_for_height_vfunc_role(Gtk::Widget &widget, int height, int &minimum_width, int &natural_width) const {
|
||||
m_renderer_text.get_preferred_width_for_height(widget, height, minimum_width, natural_width);
|
||||
}
|
||||
|
||||
void CellRendererMemberList::get_preferred_height_vfunc_role(Gtk::Widget &widget, int &minimum_height, int &natural_height) const {
|
||||
m_renderer_text.get_preferred_height(widget, minimum_height, natural_height);
|
||||
}
|
||||
|
||||
void CellRendererMemberList::get_preferred_height_for_width_vfunc_role(Gtk::Widget &widget, int width, int &minimum_height, int &natural_height) const {
|
||||
m_renderer_text.get_preferred_height_for_width(widget, width, minimum_height, natural_height);
|
||||
}
|
||||
|
||||
void CellRendererMemberList::render_vfunc_role(const Cairo::RefPtr<Cairo::Context> &cr, Gtk::Widget &widget, const Gdk::Rectangle &background_area, const Gdk::Rectangle &cell_area, Gtk::CellRendererState flags) {
|
||||
m_renderer_text.render(cr, widget, background_area, cell_area, flags);
|
||||
}
|
||||
|
||||
void CellRendererMemberList::get_preferred_width_vfunc_member(Gtk::Widget &widget, int &minimum_width, int &natural_width) const {
|
||||
m_renderer_text.get_preferred_width(widget, minimum_width, natural_width);
|
||||
}
|
||||
|
||||
void CellRendererMemberList::get_preferred_width_for_height_vfunc_member(Gtk::Widget &widget, int height, int &minimum_width, int &natural_width) const {
|
||||
m_renderer_text.get_preferred_width_for_height(widget, height, minimum_width, natural_width);
|
||||
}
|
||||
|
||||
void CellRendererMemberList::get_preferred_height_vfunc_member(Gtk::Widget &widget, int &minimum_height, int &natural_height) const {
|
||||
m_renderer_text.get_preferred_height(widget, minimum_height, natural_height);
|
||||
}
|
||||
|
||||
void CellRendererMemberList::get_preferred_height_for_width_vfunc_member(Gtk::Widget &widget, int width, int &minimum_height, int &natural_height) const {
|
||||
m_renderer_text.get_preferred_height_for_width(widget, width, minimum_height, natural_height);
|
||||
}
|
||||
|
||||
void CellRendererMemberList::render_vfunc_member(const Cairo::RefPtr<Cairo::Context> &cr, Gtk::Widget &widget, const Gdk::Rectangle &background_area, const Gdk::Rectangle &cell_area, Gtk::CellRendererState flags) {
|
||||
m_renderer_text.render(cr, widget, background_area, cell_area, flags);
|
||||
}
|
56
src/components/cellrenderermemberlist.hpp
Normal file
56
src/components/cellrenderermemberlist.hpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
#pragma once
|
||||
#include <gtkmm/cellrenderer.h>
|
||||
|
||||
enum class MemberListRenderType : uint8_t {
|
||||
Role,
|
||||
Member,
|
||||
};
|
||||
|
||||
class CellRendererMemberList : public Gtk::CellRenderer {
|
||||
public:
|
||||
CellRendererMemberList();
|
||||
~CellRendererMemberList() override = default;
|
||||
|
||||
Glib::PropertyProxy<MemberListRenderType> property_type();
|
||||
Glib::PropertyProxy<uint64_t> property_id();
|
||||
Glib::PropertyProxy<Glib::ustring> property_name();
|
||||
|
||||
protected:
|
||||
void get_preferred_width_vfunc(Gtk::Widget &widget, int &minimum_width, int &natural_width) const override;
|
||||
void get_preferred_width_for_height_vfunc(Gtk::Widget &widget, int height, int &minimum_width, int &natural_width) const override;
|
||||
void get_preferred_height_vfunc(Gtk::Widget &widget, int &minimum_height, int &natural_height) const override;
|
||||
void get_preferred_height_for_width_vfunc(Gtk::Widget &widget, int width, int &minimum_height, int &natural_height) const override;
|
||||
void render_vfunc(const Cairo::RefPtr<Cairo::Context> &cr,
|
||||
Gtk::Widget &widget,
|
||||
const Gdk::Rectangle &background_area,
|
||||
const Gdk::Rectangle &cell_area,
|
||||
Gtk::CellRendererState flags) override;
|
||||
|
||||
void get_preferred_width_vfunc_role(Gtk::Widget &widget, int &minimum_width, int &natural_width) const;
|
||||
void get_preferred_width_for_height_vfunc_role(Gtk::Widget &widget, int height, int &minimum_width, int &natural_width) const;
|
||||
void get_preferred_height_vfunc_role(Gtk::Widget &widget, int &minimum_height, int &natural_height) const;
|
||||
void get_preferred_height_for_width_vfunc_role(Gtk::Widget &widget, int width, int &minimum_height, int &natural_height) const;
|
||||
void render_vfunc_role(const Cairo::RefPtr<Cairo::Context> &cr,
|
||||
Gtk::Widget &widget,
|
||||
const Gdk::Rectangle &background_area,
|
||||
const Gdk::Rectangle &cell_area,
|
||||
Gtk::CellRendererState flags);
|
||||
|
||||
void get_preferred_width_vfunc_member(Gtk::Widget &widget, int &minimum_width, int &natural_width) const;
|
||||
void get_preferred_width_for_height_vfunc_member(Gtk::Widget &widget, int height, int &minimum_width, int &natural_width) const;
|
||||
void get_preferred_height_vfunc_member(Gtk::Widget &widget, int &minimum_height, int &natural_height) const;
|
||||
void get_preferred_height_for_width_vfunc_member(Gtk::Widget &widget, int width, int &minimum_height, int &natural_height) const;
|
||||
void render_vfunc_member(const Cairo::RefPtr<Cairo::Context> &cr,
|
||||
Gtk::Widget &widget,
|
||||
const Gdk::Rectangle &background_area,
|
||||
const Gdk::Rectangle &cell_area,
|
||||
Gtk::CellRendererState flags);
|
||||
|
||||
private:
|
||||
Gtk::CellRendererText m_renderer_text;
|
||||
Gtk::CellRendererPixbuf m_renderer_pixbuf;
|
||||
|
||||
Glib::Property<MemberListRenderType> m_property_type;
|
||||
Glib::Property<uint64_t> m_property_id;
|
||||
Glib::Property<Glib::ustring> m_property_name;
|
||||
};
|
|
@ -1,233 +1,148 @@
|
|||
#include "memberlist.hpp"
|
||||
#include "lazyimage.hpp"
|
||||
#include "statusindicator.hpp"
|
||||
|
||||
constexpr static const int MaxMemberListRows = 200;
|
||||
MemberList::MemberList()
|
||||
: m_model(Gtk::TreeStore::create(m_columns)) {
|
||||
m_main.get_style_context()->add_class("member-list");
|
||||
|
||||
MemberListUserRow::MemberListUserRow(const std::optional<GuildData> &guild, const UserData &data) {
|
||||
ID = data.ID;
|
||||
m_ev = Gtk::manage(new Gtk::EventBox);
|
||||
m_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
|
||||
m_label = Gtk::manage(new Gtk::Label);
|
||||
m_avatar = Gtk::manage(new LazyImage(16, 16));
|
||||
m_status_indicator = Gtk::manage(new StatusIndicator(ID));
|
||||
m_view.set_hexpand(true);
|
||||
m_view.set_vexpand(true);
|
||||
|
||||
if (Abaddon::Get().GetSettings().ShowOwnerCrown && guild.has_value() && guild->OwnerID == data.ID) {
|
||||
try {
|
||||
const static auto crown_path = Abaddon::GetResPath("/crown.png");
|
||||
auto pixbuf = Gdk::Pixbuf::create_from_file(crown_path, 12, 12);
|
||||
m_crown = Gtk::manage(new Gtk::Image(pixbuf));
|
||||
m_crown->set_valign(Gtk::ALIGN_CENTER);
|
||||
m_crown->set_margin_end(8);
|
||||
} catch (...) {}
|
||||
}
|
||||
m_view.set_show_expanders(false);
|
||||
m_view.set_enable_search(false);
|
||||
m_view.set_headers_visible(false);
|
||||
m_view.get_selection()->set_mode(Gtk::SELECTION_NONE);
|
||||
m_view.set_model(m_model);
|
||||
|
||||
m_status_indicator->set_margin_start(3);
|
||||
m_main.add(m_view);
|
||||
m_main.show_all_children();
|
||||
|
||||
if (guild.has_value())
|
||||
m_avatar->SetURL(data.GetAvatarURL(guild->ID, "png"));
|
||||
else
|
||||
m_avatar->SetURL(data.GetAvatarURL("png"));
|
||||
|
||||
get_style_context()->add_class("members-row");
|
||||
get_style_context()->add_class("members-row-member");
|
||||
m_label->get_style_context()->add_class("members-row-label");
|
||||
m_avatar->get_style_context()->add_class("members-row-avatar");
|
||||
|
||||
m_label->set_single_line_mode(true);
|
||||
m_label->set_ellipsize(Pango::ELLIPSIZE_END);
|
||||
|
||||
// todo remove after migration complete
|
||||
std::string display;
|
||||
if (data.IsPomelo()) {
|
||||
display = data.GetDisplayName(guild.has_value() ? guild->ID : Snowflake::Invalid);
|
||||
} else {
|
||||
display = data.Username;
|
||||
if (Abaddon::Get().GetSettings().ShowMemberListDiscriminators) {
|
||||
display += "#" + data.Discriminator;
|
||||
}
|
||||
}
|
||||
|
||||
if (guild.has_value()) {
|
||||
if (const auto col_id = data.GetHoistedRole(guild->ID, true); col_id.IsValid()) {
|
||||
auto color = Abaddon::Get().GetDiscordClient().GetRole(col_id)->Color;
|
||||
m_label->set_use_markup(true);
|
||||
m_label->set_markup("<span color='#" + IntToCSSColor(color) + "'>" + Glib::Markup::escape_text(display) + "</span>");
|
||||
} else {
|
||||
m_label->set_text(display);
|
||||
}
|
||||
} else {
|
||||
m_label->set_text(display);
|
||||
}
|
||||
|
||||
m_label->set_halign(Gtk::ALIGN_START);
|
||||
m_box->add(*m_avatar);
|
||||
m_box->add(*m_status_indicator);
|
||||
m_box->add(*m_label);
|
||||
if (m_crown != nullptr)
|
||||
m_box->add(*m_crown);
|
||||
m_ev->add(*m_box);
|
||||
add(*m_ev);
|
||||
show_all();
|
||||
auto *column = Gtk::make_managed<Gtk::TreeView::Column>("display");
|
||||
auto *renderer = Gtk::make_managed<CellRendererMemberList>();
|
||||
column->pack_start(*renderer);
|
||||
column->add_attribute(renderer->property_type(), m_columns.m_type);
|
||||
column->add_attribute(renderer->property_id(), m_columns.m_id);
|
||||
column->add_attribute(renderer->property_name(), m_columns.m_name);
|
||||
m_view.append_column(*column);
|
||||
}
|
||||
|
||||
MemberList::MemberList() {
|
||||
m_main = Gtk::manage(new Gtk::ScrolledWindow);
|
||||
m_listbox = Gtk::manage(new Gtk::ListBox);
|
||||
|
||||
m_listbox->get_style_context()->add_class("members");
|
||||
|
||||
m_listbox->set_selection_mode(Gtk::SELECTION_NONE);
|
||||
|
||||
m_main->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
|
||||
m_main->add(*m_listbox);
|
||||
m_main->show_all();
|
||||
}
|
||||
|
||||
Gtk::Widget *MemberList::GetRoot() const {
|
||||
return m_main;
|
||||
}
|
||||
|
||||
void MemberList::Clear() {
|
||||
SetActiveChannel(Snowflake::Invalid);
|
||||
UpdateMemberList();
|
||||
}
|
||||
|
||||
void MemberList::SetActiveChannel(Snowflake id) {
|
||||
m_chan_id = id;
|
||||
m_guild_id = Snowflake::Invalid;
|
||||
if (m_chan_id.IsValid()) {
|
||||
const auto chan = Abaddon::Get().GetDiscordClient().GetChannel(id);
|
||||
if (chan.has_value() && chan->GuildID.has_value()) m_guild_id = *chan->GuildID;
|
||||
}
|
||||
Gtk::Widget *MemberList::GetRoot() {
|
||||
return &m_main;
|
||||
}
|
||||
|
||||
void MemberList::UpdateMemberList() {
|
||||
m_id_to_row.clear();
|
||||
|
||||
auto children = m_listbox->get_children();
|
||||
auto it = children.begin();
|
||||
while (it != children.end()) {
|
||||
delete *it;
|
||||
it++;
|
||||
}
|
||||
|
||||
if (!Abaddon::Get().GetDiscordClient().IsStarted()) return;
|
||||
if (!m_chan_id.IsValid()) return;
|
||||
Clear();
|
||||
if (!m_active_channel.IsValid()) return;
|
||||
|
||||
auto &discord = Abaddon::Get().GetDiscordClient();
|
||||
const auto chan = discord.GetChannel(m_chan_id);
|
||||
if (!chan.has_value()) return;
|
||||
if (chan->Type == ChannelType::DM || chan->Type == ChannelType::GROUP_DM) {
|
||||
int num_rows = 0;
|
||||
for (const auto &user : chan->GetDMRecipients()) {
|
||||
if (num_rows++ > MaxMemberListRows) break;
|
||||
auto *row = Gtk::manage(new MemberListUserRow(std::nullopt, user));
|
||||
m_id_to_row[user.ID] = row;
|
||||
AttachUserMenuHandler(row, user.ID);
|
||||
m_listbox->add(*row);
|
||||
}
|
||||
|
||||
const auto channel = discord.GetChannel(m_active_channel);
|
||||
if (!channel.has_value()) {
|
||||
spdlog::get("ui")->warn("attempted to update member list with unfetchable channel");
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<Snowflake> ids;
|
||||
if (chan->IsThread()) {
|
||||
const auto x = discord.GetUsersInThread(m_chan_id);
|
||||
ids = { x.begin(), x.end() };
|
||||
} else
|
||||
ids = discord.GetUsersInGuild(m_guild_id);
|
||||
if (channel->IsDM()) {
|
||||
for (const auto &user : channel->GetDMRecipients()) {
|
||||
auto row = *m_model->append();
|
||||
row[m_columns.m_type] = MemberListRenderType::Member;
|
||||
row[m_columns.m_id] = user.ID;
|
||||
row[m_columns.m_name] = user.GetDisplayNameEscaped();
|
||||
}
|
||||
}
|
||||
|
||||
const auto guild = discord.GetGuild(m_active_guild);
|
||||
if (!guild.has_value()) return;
|
||||
|
||||
std::set<Snowflake> ids;
|
||||
if (channel->IsThread()) {
|
||||
const auto x = discord.GetUsersInThread(m_active_channel);
|
||||
ids = { x.begin(), x.end() };
|
||||
} else {
|
||||
ids = discord.GetUsersInGuild(m_active_guild);
|
||||
}
|
||||
|
||||
// process all the shit first so its in proper order
|
||||
std::map<int, RoleData> pos_to_role;
|
||||
std::map<int, std::vector<UserData>> pos_to_users;
|
||||
std::unordered_map<Snowflake, int> user_to_color;
|
||||
std::vector<Snowflake> roleless_users;
|
||||
|
||||
for (const auto &id : ids) {
|
||||
auto user = discord.GetUser(id);
|
||||
if (!user.has_value() || user->IsDeleted())
|
||||
continue;
|
||||
for (const auto user_id : ids) {
|
||||
auto user = discord.GetUser(user_id);
|
||||
if (!user.has_value() || user->IsDeleted()) continue;
|
||||
|
||||
auto pos_role_id = discord.GetMemberHoistedRole(m_guild_id, id); // role for positioning
|
||||
auto col_role_id = discord.GetMemberHoistedRole(m_guild_id, id, true); // role for color
|
||||
auto pos_role = discord.GetRole(pos_role_id);
|
||||
auto col_role = discord.GetRole(col_role_id);
|
||||
const auto pos_role_id = discord.GetMemberHoistedRole(m_active_guild, user_id);
|
||||
const auto col_role_id = discord.GetMemberHoistedRole(m_active_guild, user_id, true);
|
||||
const auto pos_role = discord.GetRole(pos_role_id);
|
||||
const auto col_role = discord.GetRole(col_role_id);
|
||||
|
||||
if (!pos_role.has_value()) {
|
||||
roleless_users.push_back(id);
|
||||
roleless_users.push_back(user_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
pos_to_role[pos_role->Position] = *pos_role;
|
||||
pos_to_users[pos_role->Position].push_back(std::move(*user));
|
||||
if (col_role.has_value())
|
||||
user_to_color[id] = col_role->Color;
|
||||
if (col_role.has_value()) user_to_color[user_id] = col_role->Color;
|
||||
}
|
||||
|
||||
int num_rows = 0;
|
||||
const auto guild = discord.GetGuild(m_guild_id);
|
||||
if (!guild.has_value()) return;
|
||||
auto add_user = [this, &num_rows, guild](const UserData &data) -> bool {
|
||||
if (num_rows++ > MaxMemberListRows) return false;
|
||||
auto *row = Gtk::manage(new MemberListUserRow(*guild, data));
|
||||
m_id_to_row[data.ID] = row;
|
||||
AttachUserMenuHandler(row, data.ID);
|
||||
m_listbox->add(*row);
|
||||
return true;
|
||||
const auto add_user = [this, &guild](const UserData &user, const Gtk::TreeRow &parent) {
|
||||
auto row = *m_model->append(parent->children());
|
||||
row[m_columns.m_type] = MemberListRenderType::Member;
|
||||
row[m_columns.m_id] = user.ID;
|
||||
row[m_columns.m_name] = user.GetDisplayNameEscaped();
|
||||
return row;
|
||||
};
|
||||
|
||||
auto add_role = [this](const std::string &name) {
|
||||
auto *role_row = Gtk::manage(new Gtk::ListBoxRow);
|
||||
auto *role_lbl = Gtk::manage(new Gtk::Label);
|
||||
|
||||
role_row->get_style_context()->add_class("members-row");
|
||||
role_row->get_style_context()->add_class("members-row-role");
|
||||
role_lbl->get_style_context()->add_class("members-row-label");
|
||||
|
||||
role_lbl->set_single_line_mode(true);
|
||||
role_lbl->set_ellipsize(Pango::ELLIPSIZE_END);
|
||||
role_lbl->set_use_markup(true);
|
||||
role_lbl->set_markup("<b>" + Glib::Markup::escape_text(name) + "</b>");
|
||||
role_lbl->set_halign(Gtk::ALIGN_START);
|
||||
role_row->add(*role_lbl);
|
||||
role_row->show_all();
|
||||
m_listbox->add(*role_row);
|
||||
const auto add_role = [this](const RoleData &role) {
|
||||
auto row = *m_model->append();
|
||||
row[m_columns.m_type] = MemberListRenderType::Role;
|
||||
row[m_columns.m_id] = role.ID;
|
||||
row[m_columns.m_name] = role.GetEscapedName();
|
||||
return row;
|
||||
};
|
||||
|
||||
for (auto it = pos_to_role.crbegin(); it != pos_to_role.crend(); it++) {
|
||||
auto pos = it->first;
|
||||
const auto pos = it->first;
|
||||
const auto &role = it->second;
|
||||
|
||||
add_role(role.Name);
|
||||
auto role_row = add_role(role);
|
||||
|
||||
if (pos_to_users.find(pos) == pos_to_users.end()) continue;
|
||||
|
||||
auto &users = pos_to_users.at(pos);
|
||||
AlphabeticalSort(users.begin(), users.end(), [](const auto &e) { return e.Username; });
|
||||
|
||||
for (const auto &data : users)
|
||||
if (!add_user(data)) return;
|
||||
for (const auto &user : users) add_user(user, role_row);
|
||||
}
|
||||
|
||||
if (chan->Type == ChannelType::DM || chan->Type == ChannelType::GROUP_DM)
|
||||
add_role("Users");
|
||||
else
|
||||
add_role("@everyone");
|
||||
for (const auto &id : roleless_users) {
|
||||
auto everyone_role = *m_model->append();
|
||||
everyone_role[m_columns.m_type] = MemberListRenderType::Role;
|
||||
everyone_role[m_columns.m_id] = m_active_guild; // yes thats how the role works
|
||||
everyone_role[m_columns.m_name] = "@everyone";
|
||||
|
||||
for (const auto id : roleless_users) {
|
||||
const auto user = discord.GetUser(id);
|
||||
if (user.has_value())
|
||||
if (!add_user(*user)) return;
|
||||
if (user.has_value()) add_user(*user, everyone_role);
|
||||
}
|
||||
|
||||
m_view.expand_all();
|
||||
}
|
||||
|
||||
void MemberList::Clear() {
|
||||
m_model->clear();
|
||||
}
|
||||
|
||||
void MemberList::SetActiveChannel(Snowflake id) {
|
||||
m_active_channel = id;
|
||||
m_active_guild = Snowflake::Invalid;
|
||||
if (m_active_channel.IsValid()) {
|
||||
const auto channel = Abaddon::Get().GetDiscordClient().GetChannel(m_active_channel);
|
||||
if (channel.has_value() && channel->GuildID.has_value()) m_active_guild = *channel->GuildID;
|
||||
}
|
||||
}
|
||||
|
||||
void MemberList::AttachUserMenuHandler(Gtk::ListBoxRow *row, Snowflake id) {
|
||||
row->signal_button_press_event().connect([this, id](GdkEventButton *e) -> bool {
|
||||
if (e->type == GDK_BUTTON_PRESS && e->button == GDK_BUTTON_SECONDARY) {
|
||||
Abaddon::Get().ShowUserMenu(reinterpret_cast<const GdkEvent *>(e), id, m_guild_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
MemberList::ModelColumns::ModelColumns() {
|
||||
add(m_type);
|
||||
add(m_id);
|
||||
add(m_name);
|
||||
}
|
||||
|
|
|
@ -1,43 +1,36 @@
|
|||
#pragma once
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <optional>
|
||||
#include "discord/discord.hpp"
|
||||
#include <gtkmm/treemodel.h>
|
||||
#include <gtkmm/treestore.h>
|
||||
#include <gtkmm/treeview.h>
|
||||
|
||||
class LazyImage;
|
||||
class StatusIndicator;
|
||||
class MemberListUserRow : public Gtk::ListBoxRow {
|
||||
public:
|
||||
MemberListUserRow(const std::optional<GuildData> &guild, const UserData &data);
|
||||
|
||||
Snowflake ID;
|
||||
|
||||
private:
|
||||
Gtk::EventBox *m_ev;
|
||||
Gtk::Box *m_box;
|
||||
LazyImage *m_avatar;
|
||||
StatusIndicator *m_status_indicator;
|
||||
Gtk::Label *m_label;
|
||||
Gtk::Image *m_crown = nullptr;
|
||||
};
|
||||
#include "cellrenderermemberlist.hpp"
|
||||
#include "discord/snowflake.hpp"
|
||||
|
||||
class MemberList {
|
||||
public:
|
||||
MemberList();
|
||||
Gtk::Widget *GetRoot() const;
|
||||
Gtk::Widget *GetRoot();
|
||||
|
||||
void UpdateMemberList();
|
||||
void Clear();
|
||||
void SetActiveChannel(Snowflake id);
|
||||
|
||||
private:
|
||||
void AttachUserMenuHandler(Gtk::ListBoxRow *row, Snowflake id);
|
||||
class ModelColumns : public Gtk::TreeModel::ColumnRecord {
|
||||
public:
|
||||
ModelColumns();
|
||||
|
||||
Gtk::ScrolledWindow *m_main;
|
||||
Gtk::ListBox *m_listbox;
|
||||
Gtk::TreeModelColumn<MemberListRenderType> m_type;
|
||||
Gtk::TreeModelColumn<uint64_t> m_id;
|
||||
Gtk::TreeModelColumn<Glib::ustring> m_name;
|
||||
};
|
||||
|
||||
Snowflake m_guild_id;
|
||||
Snowflake m_chan_id;
|
||||
ModelColumns m_columns;
|
||||
Glib::RefPtr<Gtk::TreeStore> m_model;
|
||||
Gtk::TreeView m_view;
|
||||
|
||||
std::unordered_map<Snowflake, Gtk::ListBoxRow *> m_id_to_row;
|
||||
Gtk::ScrolledWindow m_main;
|
||||
|
||||
Snowflake m_active_channel;
|
||||
Snowflake m_active_guild;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user