diff --git a/chatterino.pro b/chatterino.pro index 131696679..9d7119797 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -261,7 +261,8 @@ SOURCES += \ src/messages/MessageContainer.cpp \ src/debug/Benchmark.cpp \ src/common/UsernameSet.cpp \ - src/widgets/settingspages/AdvancedPage.cpp + src/widgets/settingspages/AdvancedPage.cpp \ + src/widgets/splits/ClosedSplits.cpp HEADERS += \ src/Application.hpp \ @@ -462,7 +463,8 @@ HEADERS += \ src/widgets/helper/Button.hpp \ src/messages/MessageContainer.hpp \ src/common/UsernameSet.hpp \ - src/widgets/settingspages/AdvancedPage.hpp + src/widgets/settingspages/AdvancedPage.hpp \ + src/widgets/splits/ClosedSplits.hpp RESOURCES += \ resources/resources.qrc \ diff --git a/src/widgets/Window.cpp b/src/widgets/Window.cpp index 22a326ebf..3f6ebdd98 100644 --- a/src/widgets/Window.cpp +++ b/src/widgets/Window.cpp @@ -15,8 +15,10 @@ #include "widgets/dialogs/UpdateDialog.hpp" #include "widgets/dialogs/WelcomeDialog.hpp" #include "widgets/helper/EffectLabel.hpp" +#include "widgets/helper/NotebookTab.hpp" #include "widgets/helper/Shortcut.hpp" #include "widgets/helper/TitlebarButton.hpp" +#include "widgets/splits/ClosedSplits.hpp" #include "widgets/splits/Split.hpp" #include "widgets/splits/SplitContainer.hpp" @@ -304,6 +306,26 @@ void Window::addShortcuts() // Close tab createWindowShortcut(this, "CTRL+SHIFT+W", [this] { this->notebook_->removeCurrentPage(); }); + + // Reopen last closed split + createWindowShortcut(this, "CTRL+G", [this] { + if (ClosedSplits::empty()) { + return; + } + ClosedSplits::SplitInfo si = ClosedSplits::pop(); + SplitContainer *splitContainer{nullptr}; + if (si.tab) { + splitContainer = dynamic_cast(si.tab->page); + } + if (!splitContainer) { + splitContainer = this->notebook_->getOrAddSelectedPage(); + } + this->notebook_->select(splitContainer); + Split *split = new Split(splitContainer); + splitContainer->appendSplit(split); + split->setChannel( + getApp()->twitch.server->getOrAddChannel(si.channelName)); + }); } #define UGLYMACROHACK1(s) #s diff --git a/src/widgets/splits/ClosedSplits.cpp b/src/widgets/splits/ClosedSplits.cpp new file mode 100644 index 000000000..2c1d912c9 --- /dev/null +++ b/src/widgets/splits/ClosedSplits.cpp @@ -0,0 +1,52 @@ +#include "ClosedSplits.hpp" + +namespace chatterino { + +std::mutex ClosedSplits::m_; +std::vector ClosedSplits::closedSplits_; + +void ClosedSplits::invalidateTab(NotebookTab *const tab) +{ + std::lock_guard lk(ClosedSplits::m_); + auto it = std::find_if( + ClosedSplits::closedSplits_.begin(), ClosedSplits::closedSplits_.end(), + [tab](const auto &item) -> bool { return item.tab == tab; }); + if (it == ClosedSplits::closedSplits_.end()) { + return; + } + it->tab = nullptr; +} + +void ClosedSplits::push(const SplitInfo &si) +{ + std::lock_guard lk(ClosedSplits::m_); + ClosedSplits::closedSplits_.push_back(si); +} + +void ClosedSplits::push(SplitInfo &&si) +{ + std::lock_guard lk(ClosedSplits::m_); + ClosedSplits::closedSplits_.push_back(std::move(si)); +} + +ClosedSplits::SplitInfo ClosedSplits::pop() +{ + std::lock_guard lk(ClosedSplits::m_); + SplitInfo si = std::move(ClosedSplits::closedSplits_.back()); + ClosedSplits::closedSplits_.pop_back(); + return si; +} + +bool ClosedSplits::empty() +{ + std::lock_guard lk(ClosedSplits::m_); + return ClosedSplits::closedSplits_.empty(); +} + +std::size_t ClosedSplits::size() +{ + std::lock_guard lk(ClosedSplits::m_); + return ClosedSplits::closedSplits_.size(); +} + +} // namespace chatterino diff --git a/src/widgets/splits/ClosedSplits.hpp b/src/widgets/splits/ClosedSplits.hpp new file mode 100644 index 000000000..4d05f22c0 --- /dev/null +++ b/src/widgets/splits/ClosedSplits.hpp @@ -0,0 +1,35 @@ +#ifndef CLOSEDSPLITS_HPP +#define CLOSEDSPLITS_HPP + +#include "common/Channel.hpp" +#include "widgets/helper/NotebookTab.hpp" + +#include +#include +#include + +namespace chatterino { + +class ClosedSplits +{ +public: + struct SplitInfo { + QString channelName; + NotebookTab *tab; // non owning ptr + }; + + static void invalidateTab(NotebookTab *const tab); + static void push(const SplitInfo &si); + static void push(SplitInfo &&si); + static SplitInfo pop(); + static bool empty(); + static std::size_t size(); + +private: + static std::mutex m_; + static std::vector closedSplits_; +}; + +} // namespace chatterino + +#endif // CLOSEDSPLITS_HPP diff --git a/src/widgets/splits/Split.cpp b/src/widgets/splits/Split.cpp index d67652d58..6477a1e79 100644 --- a/src/widgets/splits/Split.cpp +++ b/src/widgets/splits/Split.cpp @@ -19,9 +19,11 @@ #include "widgets/dialogs/UserInfoPopup.hpp" #include "widgets/helper/ChannelView.hpp" #include "widgets/helper/DebugPopup.hpp" +#include "widgets/helper/NotebookTab.hpp" #include "widgets/helper/ResizingTextEdit.hpp" #include "widgets/helper/SearchPopup.hpp" #include "widgets/helper/Shortcut.hpp" +#include "widgets/splits/ClosedSplits.hpp" #include "widgets/splits/SplitContainer.hpp" #include "widgets/splits/SplitHeader.hpp" #include "widgets/splits/SplitInput.hpp" @@ -415,6 +417,10 @@ void Split::deleteFromContainer() { if (this->container_) { this->container_->deleteSplit(this); + auto *tab = this->getContainer()->getTab(); + tab->connect(tab, &QWidget::destroyed, + [tab]() mutable { ClosedSplits::invalidateTab(tab); }); + ClosedSplits::push({this->getChannel()->getName(), tab}); } }