#pragma once #include #include #include "discord/message.hpp" #include "discord/snowflake.hpp" class ChatList : public Gtk::ScrolledWindow { public: ChatList(); void Clear(); void SetActiveChannel(Snowflake id); template void SetMessages(Iter begin, Iter end); template void PrependMessages(Iter begin, Iter end); void ProcessNewMessage(const Message &data, bool prepend); void DeleteMessage(Snowflake id); void RefetchMessage(Snowflake id); Snowflake GetOldestListedMessage(); void UpdateMessageReactions(Snowflake id); void SetFailedByNonce(const std::string &nonce); std::vector GetRecentAuthors(); void SetSeparateAll(bool separate); void SetUsePinnedMenu(); // i think i need a better way to do menus void ActuallyRemoveMessage(Snowflake id); // perhaps not the best method name private: void SetupMenu(); void ScrollToBottom(); void OnVAdjustmentValueChanged(); void OnVAdjustmentUpperChanged(); void OnListSizeAllocate(Gtk::Allocation &allocation); void RemoveMessageAndHeader(Gtk::Widget *widget); bool m_use_pinned_menu = false; Gtk::Menu m_menu; Gtk::MenuItem *m_menu_copy_id; Gtk::MenuItem *m_menu_copy_content; Gtk::MenuItem *m_menu_delete_message; Gtk::MenuItem *m_menu_edit_message; Gtk::MenuItem *m_menu_reply_to; Gtk::MenuItem *m_menu_unpin; Gtk::MenuItem *m_menu_pin; Snowflake m_menu_selected_message; Snowflake m_active_channel; int m_num_messages = 0; int m_num_rows = 0; std::map m_id_to_widget; bool m_ignore_next_upper = false; double m_old_upper = -1.0; bool m_should_scroll_to_bottom = true; Gtk::ListBox m_list; bool m_separate_all = false; Glib::Timer m_history_timer; public: // these are all forwarded by the parent using type_signal_action_message_edit = sigc::signal; using type_signal_action_chat_load_history = sigc::signal; using type_signal_action_channel_click = sigc::signal; using type_signal_action_insert_mention = sigc::signal; using type_signal_action_open_user_menu = sigc::signal; using type_signal_action_reaction_add = sigc::signal; using type_signal_action_reaction_remove = sigc::signal; using type_signal_action_reply_to = sigc::signal; type_signal_action_message_edit signal_action_message_edit(); type_signal_action_chat_load_history signal_action_chat_load_history(); type_signal_action_channel_click signal_action_channel_click(); type_signal_action_insert_mention signal_action_insert_mention(); type_signal_action_open_user_menu signal_action_open_user_menu(); type_signal_action_reaction_add signal_action_reaction_add(); type_signal_action_reaction_remove signal_action_reaction_remove(); type_signal_action_reply_to signal_action_reply_to(); private: type_signal_action_message_edit m_signal_action_message_edit; type_signal_action_chat_load_history m_signal_action_chat_load_history; type_signal_action_channel_click m_signal_action_channel_click; type_signal_action_insert_mention m_signal_action_insert_mention; type_signal_action_open_user_menu m_signal_action_open_user_menu; type_signal_action_reaction_add m_signal_action_reaction_add; type_signal_action_reaction_remove m_signal_action_reaction_remove; type_signal_action_reply_to m_signal_action_reply_to; }; template inline void ChatList::SetMessages(Iter begin, Iter end) { Clear(); m_num_rows = 0; m_num_messages = 0; m_id_to_widget.clear(); for (Iter it = begin; it != end; it++) ProcessNewMessage(*it, false); ScrollToBottom(); } template inline void ChatList::PrependMessages(Iter begin, Iter end) { for (Iter it = begin; it != end; it++) ProcessNewMessage(*it, true); }