diff options
author | ouwou <26526779+ouwou@users.noreply.github.com> | 2020-08-28 18:21:08 -0400 |
---|---|---|
committer | ouwou <26526779+ouwou@users.noreply.github.com> | 2020-08-28 18:21:08 -0400 |
commit | 5b7d36bb7438f32b56d6ebdf043ee291332060f1 (patch) | |
tree | f243bab9cd2d845e9958353c2f89d9bc0aa42eec /components | |
parent | 8699a547f3d51504cd0aa695f580315b8fe27678 (diff) | |
download | abaddon-portaudio-5b7d36bb7438f32b56d6ebdf043ee291332060f1.tar.gz abaddon-portaudio-5b7d36bb7438f32b56d6ebdf043ee291332060f1.zip |
scroll up to load more messages
Diffstat (limited to 'components')
-rw-r--r-- | components/chatmessage.cpp | 5 | ||||
-rw-r--r-- | components/chatmessage.hpp | 1 | ||||
-rw-r--r-- | components/chatwindow.cpp | 62 | ||||
-rw-r--r-- | components/chatwindow.hpp | 9 |
4 files changed, 71 insertions, 6 deletions
diff --git a/components/chatmessage.cpp b/components/chatmessage.cpp index b03c6d6..893a464 100644 --- a/components/chatmessage.cpp +++ b/components/chatmessage.cpp @@ -57,3 +57,8 @@ void ChatMessageTextItem::AppendNewContent(std::string content) { auto buf = m_text->get_buffer(); buf->set_text(buf->get_text() + "\n" + content); } + +void ChatMessageTextItem::PrependNewContent(std::string content) { + auto buf = m_text->get_buffer(); + buf->set_text(content + "\n" + buf->get_text()); +} diff --git a/components/chatmessage.hpp b/components/chatmessage.hpp index e9d58a4..227e272 100644 --- a/components/chatmessage.hpp +++ b/components/chatmessage.hpp @@ -17,6 +17,7 @@ class ChatMessageTextItem : public ChatMessageItem { public: ChatMessageTextItem(const MessageData *data); void AppendNewContent(std::string content); + void PrependNewContent(std::string content); protected: Gtk::Box *m_main_box; diff --git a/components/chatwindow.cpp b/components/chatwindow.cpp index 36df514..8e2b85c 100644 --- a/components/chatwindow.cpp +++ b/components/chatwindow.cpp @@ -5,6 +5,7 @@ ChatWindow::ChatWindow() { m_message_set_dispatch.connect(sigc::mem_fun(*this, &ChatWindow::SetMessagesInternal)); m_new_message_dispatch.connect(sigc::mem_fun(*this, &ChatWindow::AddNewMessageInternal)); + m_new_history_dispatch.connect(sigc::mem_fun(*this, &ChatWindow::AddNewHistoryInternal)); m_main = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); m_listbox = Gtk::manage(new Gtk::ListBox); @@ -19,12 +20,20 @@ ChatWindow::ChatWindow() { m_main->set_vexpand(true); m_main->show(); + m_scroll->signal_edge_reached().connect(sigc::mem_fun(*this, &ChatWindow::on_scroll_edge_overshot)); + + auto vadj = m_scroll->get_vadjustment(); + vadj->signal_value_changed().connect([&, vadj]() { + m_scroll_to_bottom = vadj->get_upper() - vadj->get_page_size() <= vadj->get_value(); + }); + m_scroll->set_can_focus(false); m_scroll->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS); m_scroll->show(); m_listbox->signal_size_allocate().connect([this](Gtk::Allocation &) { - ScrollToBottom(); + if (m_scroll_to_bottom) + ScrollToBottom(); }); m_listbox->set_selection_mode(Gtk::SELECTION_NONE); @@ -96,18 +105,25 @@ ChatMessageItem *ChatWindow::CreateChatEntryComponent(const MessageData *data) { return item; } -void ChatWindow::ProcessMessage(const MessageData *data) { +void ChatWindow::ProcessMessage(const MessageData *data, bool prepend) { auto create_new_row = [&]() { auto *item = CreateChatEntryComponent(data); if (item != nullptr) { - m_listbox->add(*item); + if (prepend) + m_listbox->prepend(*item); + else + m_listbox->add(*item); m_num_rows++; } }; // if the last row's message's author is the same as the new one's, then append the new message content to the last row if (m_num_rows > 0) { - auto *item = dynamic_cast<ChatMessageItem *>(m_listbox->get_row_at_index(m_num_rows - 1)); + ChatMessageItem *item; + if (prepend) + item = dynamic_cast<ChatMessageItem *>(m_listbox->get_row_at_index(0)); + else + item = dynamic_cast<ChatMessageItem *>(m_listbox->get_row_at_index(m_num_rows - 1)); assert(item != nullptr); auto *previous_data = m_abaddon->GetDiscordClient().GetMessage(item->ID); @@ -116,7 +132,10 @@ void ChatWindow::ProcessMessage(const MessageData *data) { if ((data->Author.ID == previous_data->Author.ID) && (new_type == old_type && new_type == ChatDisplayType::Text)) { auto *text_item = dynamic_cast<ChatMessageTextItem *>(item); - text_item->AppendNewContent(data->Content); + if (prepend) + text_item->PrependNewContent(data->Content); + else + text_item->AppendNewContent(data->Content); } else { create_new_row(); } @@ -143,6 +162,11 @@ bool ChatWindow::on_key_press_event(GdkEventKey *e) { return false; } +void ChatWindow::on_scroll_edge_overshot(Gtk::PositionType pos) { + if (pos == Gtk::POS_TOP) + m_abaddon->ActionChatLoadHistory(m_active_channel); +} + void ChatWindow::SetMessages(std::unordered_set<const MessageData *> msgs) { std::scoped_lock<std::mutex> guard(m_update_mutex); m_message_set_queue.push(msgs); @@ -155,6 +179,15 @@ void ChatWindow::AddNewMessage(Snowflake id) { m_new_message_dispatch.emit(); } +void ChatWindow::AddNewHistory(const std::vector<MessageData> &msgs) { + std::scoped_lock<std::mutex> guard(m_update_mutex); + std::vector<Snowflake> x; + for (const auto &msg : msgs) + x.push_back(msg.ID); + m_new_history_queue.push(x); + m_new_history_dispatch.emit(); +} + void ChatWindow::ClearMessages() { std::scoped_lock<std::mutex> guard(m_update_mutex); m_message_set_queue.push(std::unordered_set<const MessageData *>()); @@ -178,6 +211,25 @@ void ChatWindow::AddNewMessageInternal() { ProcessMessage(data); } +// todo this keeps the scrollbar at the top +void ChatWindow::AddNewHistoryInternal() { + std::set<Snowflake> msgs; + { + std::scoped_lock<std::mutex> guard(m_update_mutex); + auto vec = m_new_history_queue.front(); + msgs = std::set<Snowflake>(vec.begin(), vec.end()); + } + + for (auto it = msgs.rbegin(); it != msgs.rend(); it++) { + ProcessMessage(m_abaddon->GetDiscordClient().GetMessage(*it), true); + } + + { + std::scoped_lock<std::mutex> guard(m_update_mutex); + m_new_history_queue.pop(); + } +} + void ChatWindow::SetMessagesInternal() { auto children = m_listbox->get_children(); auto it = children.begin(); diff --git a/components/chatwindow.hpp b/components/chatwindow.hpp index a758de9..83f5676 100644 --- a/components/chatwindow.hpp +++ b/components/chatwindow.hpp @@ -16,24 +16,31 @@ public: Snowflake GetActiveChannel() const; void SetMessages(std::unordered_set<const MessageData *> msgs); void AddNewMessage(Snowflake id); + void AddNewHistory(const std::vector<MessageData> &msgs); void ClearMessages(); protected: void ScrollToBottom(); void SetMessagesInternal(); void AddNewMessageInternal(); + void AddNewHistoryInternal(); ChatDisplayType GetMessageDisplayType(const MessageData *data); ChatMessageItem *CreateChatEntryComponentText(const MessageData *data); ChatMessageItem *CreateChatEntryComponent(const MessageData *data); - void ProcessMessage(const MessageData *data); + void ProcessMessage(const MessageData *data, bool prepend = false); int m_num_rows = 0; // youd think thered be a Gtk::ListBox::get_row_count or something but nope + bool m_scroll_to_bottom = true; + bool on_key_press_event(GdkEventKey *e); + void on_scroll_edge_overshot(Gtk::PositionType pos); Glib::Dispatcher m_message_set_dispatch; std::queue<std::unordered_set<const MessageData *>> m_message_set_queue; Glib::Dispatcher m_new_message_dispatch; std::queue<Snowflake> m_new_message_queue; + Glib::Dispatcher m_new_history_dispatch; + std::queue<std::vector<Snowflake>> m_new_history_queue; std::mutex m_update_mutex; Snowflake m_active_channel; |