Add setting to only show tabs with live channels (#4358)
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
+242
-89
@@ -92,9 +92,7 @@ NotebookTab *Notebook::addPage(QWidget *page, QString title, bool select)
|
||||
}
|
||||
|
||||
this->performLayout();
|
||||
|
||||
tab->show();
|
||||
|
||||
tab->setVisible(this->shouldShowTab(tab));
|
||||
return tab;
|
||||
}
|
||||
|
||||
@@ -216,6 +214,7 @@ void Notebook::select(QWidget *page, bool focusPage)
|
||||
this->selectedPage_ = page;
|
||||
|
||||
this->performLayout();
|
||||
this->updateTabVisibility();
|
||||
}
|
||||
|
||||
bool Notebook::containsPage(QWidget *page)
|
||||
@@ -262,45 +261,121 @@ void Notebook::selectIndex(int index, bool focusPage)
|
||||
this->select(this->items_[index].page, focusPage);
|
||||
}
|
||||
|
||||
void Notebook::selectNextTab(bool focusPage)
|
||||
void Notebook::selectVisibleIndex(int index, bool focusPage)
|
||||
{
|
||||
if (this->items_.size() <= 1)
|
||||
if (!this->tabVisibilityFilter_)
|
||||
{
|
||||
this->selectIndex(index, focusPage);
|
||||
return;
|
||||
}
|
||||
|
||||
auto index =
|
||||
(this->indexOf(this->selectedPage_) + 1) % this->items_.count();
|
||||
int i = 0;
|
||||
for (auto &item : this->items_)
|
||||
{
|
||||
if (this->tabVisibilityFilter_(item.tab))
|
||||
{
|
||||
if (i == index)
|
||||
{
|
||||
// found the index'th visible page
|
||||
this->select(item.page, focusPage);
|
||||
return;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->select(this->items_[index].page, focusPage);
|
||||
void Notebook::selectNextTab(bool focusPage)
|
||||
{
|
||||
const int size = this->items_.size();
|
||||
|
||||
if (!this->tabVisibilityFilter_)
|
||||
{
|
||||
if (size <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto index = (this->indexOf(this->selectedPage_) + 1) % size;
|
||||
this->select(this->items_[index].page, focusPage);
|
||||
return;
|
||||
}
|
||||
|
||||
// find next tab that is permitted by filter
|
||||
const int startIndex = this->indexOf(this->selectedPage_);
|
||||
|
||||
auto index = (startIndex + 1) % size;
|
||||
while (index != startIndex)
|
||||
{
|
||||
if (this->tabVisibilityFilter_(this->items_[index].tab))
|
||||
{
|
||||
this->select(this->items_[index].page, focusPage);
|
||||
return;
|
||||
}
|
||||
index = (index + 1) % size;
|
||||
}
|
||||
}
|
||||
|
||||
void Notebook::selectPreviousTab(bool focusPage)
|
||||
{
|
||||
if (this->items_.size() <= 1)
|
||||
const int size = this->items_.size();
|
||||
|
||||
if (!this->tabVisibilityFilter_)
|
||||
{
|
||||
if (size <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int index = this->indexOf(this->selectedPage_) - 1;
|
||||
if (index < 0)
|
||||
{
|
||||
index += size;
|
||||
}
|
||||
|
||||
this->select(this->items_[index].page, focusPage);
|
||||
return;
|
||||
}
|
||||
|
||||
int index = this->indexOf(this->selectedPage_) - 1;
|
||||
// find next previous tab that is permitted by filter
|
||||
const int startIndex = this->indexOf(this->selectedPage_);
|
||||
|
||||
if (index < 0)
|
||||
auto index = startIndex == 0 ? size - 1 : startIndex - 1;
|
||||
while (index != startIndex)
|
||||
{
|
||||
index += this->items_.count();
|
||||
}
|
||||
if (this->tabVisibilityFilter_(this->items_[index].tab))
|
||||
{
|
||||
this->select(this->items_[index].page, focusPage);
|
||||
return;
|
||||
}
|
||||
|
||||
this->select(this->items_[index].page, focusPage);
|
||||
index = index == 0 ? size - 1 : index - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Notebook::selectLastTab(bool focusPage)
|
||||
{
|
||||
const auto size = this->items_.size();
|
||||
if (size <= 1)
|
||||
if (!this->tabVisibilityFilter_)
|
||||
{
|
||||
const auto size = this->items_.size();
|
||||
if (size <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->select(this->items_[size - 1].page, focusPage);
|
||||
return;
|
||||
}
|
||||
|
||||
this->select(this->items_[size - 1].page, focusPage);
|
||||
// find first tab permitted by filter starting from the end
|
||||
for (auto it = this->items_.rbegin(); it != this->items_.rend(); ++it)
|
||||
{
|
||||
if (this->tabVisibilityFilter_(it->tab))
|
||||
{
|
||||
this->select(it->page, focusPage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Notebook::getPageCount() const
|
||||
@@ -329,6 +404,12 @@ QWidget *Notebook::tabAt(QPoint point, int &index, int maxWidth)
|
||||
|
||||
for (auto &item : this->items_)
|
||||
{
|
||||
if (!item.tab->isVisible())
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto rect = item.tab->getDesiredRect();
|
||||
rect.setHeight(int(this->scale() * 24));
|
||||
|
||||
@@ -381,59 +462,73 @@ void Notebook::setShowTabs(bool value)
|
||||
{
|
||||
this->showTabs_ = value;
|
||||
|
||||
this->performLayout();
|
||||
for (auto &item : this->items_)
|
||||
{
|
||||
item.tab->setHidden(!value);
|
||||
}
|
||||
|
||||
this->setShowAddButton(value);
|
||||
this->performLayout();
|
||||
|
||||
this->updateTabVisibility();
|
||||
this->updateTabVisibilityMenuAction();
|
||||
|
||||
// show a popup upon hiding tabs
|
||||
if (!value && getSettings()->informOnTabVisibilityToggle.getValue())
|
||||
{
|
||||
auto unhideSeq = getApp()->hotkeys->getDisplaySequence(
|
||||
HotkeyCategory::Window, "setTabVisibility",
|
||||
{std::vector<QString>()});
|
||||
if (unhideSeq.isEmpty())
|
||||
{
|
||||
unhideSeq = getApp()->hotkeys->getDisplaySequence(
|
||||
HotkeyCategory::Window, "setTabVisibility", {{"toggle"}});
|
||||
}
|
||||
if (unhideSeq.isEmpty())
|
||||
{
|
||||
unhideSeq = getApp()->hotkeys->getDisplaySequence(
|
||||
HotkeyCategory::Window, "setTabVisibility", {{"on"}});
|
||||
}
|
||||
QString hotkeyInfo = "(currently unbound)";
|
||||
if (!unhideSeq.isEmpty())
|
||||
{
|
||||
hotkeyInfo =
|
||||
"(" +
|
||||
unhideSeq.toString(QKeySequence::SequenceFormat::NativeText) +
|
||||
")";
|
||||
}
|
||||
QMessageBox msgBox(this->window());
|
||||
msgBox.window()->setWindowTitle("Chatterino - hidden tabs");
|
||||
msgBox.setText("You've just hidden your tabs.");
|
||||
msgBox.setInformativeText(
|
||||
"You can toggle tabs by using the keyboard shortcut " + hotkeyInfo +
|
||||
" or right-clicking the tab area and selecting \"Toggle "
|
||||
"visibility of tabs\".");
|
||||
msgBox.addButton(QMessageBox::Ok);
|
||||
auto *dsaButton =
|
||||
msgBox.addButton("Don't show again", QMessageBox::YesRole);
|
||||
|
||||
msgBox.setDefaultButton(QMessageBox::Ok);
|
||||
|
||||
msgBox.exec();
|
||||
|
||||
if (msgBox.clickedButton() == dsaButton)
|
||||
{
|
||||
getSettings()->informOnTabVisibilityToggle.setValue(false);
|
||||
}
|
||||
this->showTabVisibilityInfoPopup();
|
||||
}
|
||||
}
|
||||
|
||||
void Notebook::showTabVisibilityInfoPopup()
|
||||
{
|
||||
auto unhideSeq = getApp()->hotkeys->getDisplaySequence(
|
||||
HotkeyCategory::Window, "setTabVisibility", {std::vector<QString>()});
|
||||
if (unhideSeq.isEmpty())
|
||||
{
|
||||
unhideSeq = getApp()->hotkeys->getDisplaySequence(
|
||||
HotkeyCategory::Window, "setTabVisibility", {{"toggle"}});
|
||||
}
|
||||
if (unhideSeq.isEmpty())
|
||||
{
|
||||
unhideSeq = getApp()->hotkeys->getDisplaySequence(
|
||||
HotkeyCategory::Window, "setTabVisibility", {{"on"}});
|
||||
}
|
||||
QString hotkeyInfo = "(currently unbound)";
|
||||
if (!unhideSeq.isEmpty())
|
||||
{
|
||||
hotkeyInfo =
|
||||
"(" + unhideSeq.toString(QKeySequence::SequenceFormat::NativeText) +
|
||||
")";
|
||||
}
|
||||
QMessageBox msgBox(this->window());
|
||||
msgBox.window()->setWindowTitle("Chatterino - hidden tabs");
|
||||
msgBox.setText("You've just hidden your tabs.");
|
||||
msgBox.setInformativeText(
|
||||
"You can toggle tabs by using the keyboard shortcut " + hotkeyInfo +
|
||||
" or right-clicking the tab area and selecting \"Toggle "
|
||||
"visibility of tabs\".");
|
||||
msgBox.addButton(QMessageBox::Ok);
|
||||
auto *dsaButton =
|
||||
msgBox.addButton("Don't show again", QMessageBox::YesRole);
|
||||
|
||||
msgBox.setDefaultButton(QMessageBox::Ok);
|
||||
|
||||
msgBox.exec();
|
||||
|
||||
if (msgBox.clickedButton() == dsaButton)
|
||||
{
|
||||
getSettings()->informOnTabVisibilityToggle.setValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Notebook::refresh()
|
||||
{
|
||||
this->performLayout();
|
||||
this->updateTabVisibility();
|
||||
}
|
||||
|
||||
void Notebook::updateTabVisibility()
|
||||
{
|
||||
for (auto &item : this->items_)
|
||||
{
|
||||
item.tab->setVisible(this->shouldShowTab(item.tab));
|
||||
}
|
||||
updateTabVisibilityMenuAction();
|
||||
}
|
||||
|
||||
void Notebook::updateTabVisibilityMenuAction()
|
||||
@@ -510,6 +605,21 @@ void Notebook::performLayout(bool animated)
|
||||
const auto buttonWidth = tabHeight;
|
||||
const auto buttonHeight = tabHeight - 1;
|
||||
|
||||
std::vector<Item> filteredItems;
|
||||
filteredItems.reserve(this->items_.size());
|
||||
if (this->tabVisibilityFilter_)
|
||||
{
|
||||
std::copy_if(this->items_.begin(), this->items_.end(),
|
||||
std::back_inserter(filteredItems),
|
||||
[this](const auto &item) {
|
||||
return this->tabVisibilityFilter_(item.tab);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
filteredItems.assign(this->items_.begin(), this->items_.end());
|
||||
}
|
||||
|
||||
if (this->tabLocation_ == NotebookTabLocation::Top)
|
||||
{
|
||||
auto x = left;
|
||||
@@ -535,14 +645,14 @@ void Notebook::performLayout(bool animated)
|
||||
{
|
||||
// layout tabs
|
||||
/// Notebook tabs need to know if they are in the last row.
|
||||
auto firstInBottomRow =
|
||||
this->items_.size() ? &this->items_.front() : nullptr;
|
||||
auto *firstInBottomRow =
|
||||
filteredItems.empty() ? nullptr : &filteredItems.front();
|
||||
|
||||
for (auto &item : this->items_)
|
||||
for (auto &item : filteredItems)
|
||||
{
|
||||
/// Break line if element doesn't fit.
|
||||
auto isFirst = &item == &this->items_.front();
|
||||
auto isLast = &item == &this->items_.back();
|
||||
auto isFirst = &item == &filteredItems.front();
|
||||
auto isLast = &item == &filteredItems.back();
|
||||
|
||||
auto fitsInLine = ((isLast ? addButtonWidth : 0) + x +
|
||||
item.tab->width()) <= width();
|
||||
@@ -562,7 +672,7 @@ void Notebook::performLayout(bool animated)
|
||||
|
||||
/// Update which tabs are in the last row
|
||||
auto inLastRow = false;
|
||||
for (const auto &item : this->items_)
|
||||
for (const auto &item : filteredItems)
|
||||
{
|
||||
if (&item == firstInBottomRow)
|
||||
{
|
||||
@@ -633,7 +743,7 @@ void Notebook::performLayout(bool animated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int count = this->items_.size() + (this->showAddButton_ ? 1 : 0);
|
||||
int count = filteredItems.size() + (this->showAddButton_ ? 1 : 0);
|
||||
int columnCount = ceil((float)count / tabsPerColumn);
|
||||
|
||||
// only add width of all the tabs if they are not hidden
|
||||
@@ -644,13 +754,15 @@ void Notebook::performLayout(bool animated)
|
||||
bool isLastColumn = col == columnCount - 1;
|
||||
auto largestWidth = 0;
|
||||
int tabStart = col * tabsPerColumn;
|
||||
int tabEnd = std::min((col + 1) * tabsPerColumn,
|
||||
(int)this->items_.size());
|
||||
int tabEnd =
|
||||
std::min(static_cast<size_t>((col + 1) * tabsPerColumn),
|
||||
filteredItems.size());
|
||||
|
||||
for (int i = tabStart; i < tabEnd; i++)
|
||||
{
|
||||
largestWidth = std::max(
|
||||
this->items_.at(i).tab->normalTabWidth(), largestWidth);
|
||||
largestWidth =
|
||||
std::max(filteredItems.at(i).tab->normalTabWidth(),
|
||||
largestWidth);
|
||||
}
|
||||
|
||||
if (isLastColumn && this->showAddButton_)
|
||||
@@ -664,7 +776,7 @@ void Notebook::performLayout(bool animated)
|
||||
|
||||
for (int i = tabStart; i < tabEnd; i++)
|
||||
{
|
||||
auto item = this->items_.at(i);
|
||||
auto item = filteredItems.at(i);
|
||||
|
||||
/// Layout tab
|
||||
item.tab->growWidth(largestWidth);
|
||||
@@ -735,7 +847,7 @@ void Notebook::performLayout(bool animated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int count = this->items_.size() + (this->showAddButton_ ? 1 : 0);
|
||||
int count = filteredItems.size() + (this->showAddButton_ ? 1 : 0);
|
||||
int columnCount = ceil((float)count / tabsPerColumn);
|
||||
|
||||
// only add width of all the tabs if they are not hidden
|
||||
@@ -746,13 +858,15 @@ void Notebook::performLayout(bool animated)
|
||||
bool isLastColumn = col == columnCount - 1;
|
||||
auto largestWidth = 0;
|
||||
int tabStart = col * tabsPerColumn;
|
||||
int tabEnd = std::min((col + 1) * tabsPerColumn,
|
||||
(int)this->items_.size());
|
||||
int tabEnd =
|
||||
std::min(static_cast<size_t>((col + 1) * tabsPerColumn),
|
||||
filteredItems.size());
|
||||
|
||||
for (int i = tabStart; i < tabEnd; i++)
|
||||
{
|
||||
largestWidth = std::max(
|
||||
this->items_.at(i).tab->normalTabWidth(), largestWidth);
|
||||
largestWidth =
|
||||
std::max(filteredItems.at(i).tab->normalTabWidth(),
|
||||
largestWidth);
|
||||
}
|
||||
|
||||
if (isLastColumn && this->showAddButton_)
|
||||
@@ -771,7 +885,7 @@ void Notebook::performLayout(bool animated)
|
||||
|
||||
for (int i = tabStart; i < tabEnd; i++)
|
||||
{
|
||||
auto item = this->items_.at(i);
|
||||
auto item = filteredItems.at(i);
|
||||
|
||||
/// Layout tab
|
||||
item.tab->growWidth(largestWidth);
|
||||
@@ -840,14 +954,14 @@ void Notebook::performLayout(bool animated)
|
||||
|
||||
// layout tabs
|
||||
/// Notebook tabs need to know if they are in the last row.
|
||||
auto firstInBottomRow =
|
||||
this->items_.size() ? &this->items_.front() : nullptr;
|
||||
auto *firstInBottomRow =
|
||||
filteredItems.empty() ? nullptr : &filteredItems.front();
|
||||
|
||||
for (auto &item : this->items_)
|
||||
for (auto &item : filteredItems)
|
||||
{
|
||||
/// Break line if element doesn't fit.
|
||||
auto isFirst = &item == &this->items_.front();
|
||||
auto isLast = &item == &this->items_.back();
|
||||
auto isFirst = &item == &filteredItems.front();
|
||||
auto isLast = &item == &filteredItems.back();
|
||||
|
||||
auto fitsInLine = ((isLast ? addButtonWidth : 0) + x +
|
||||
item.tab->width()) <= width();
|
||||
@@ -867,7 +981,7 @@ void Notebook::performLayout(bool animated)
|
||||
|
||||
/// Update which tabs are in the last row
|
||||
auto inLastRow = false;
|
||||
for (const auto &item : this->items_)
|
||||
for (const auto &item : filteredItems)
|
||||
{
|
||||
if (&item == firstInBottomRow)
|
||||
{
|
||||
@@ -1046,6 +1160,28 @@ size_t Notebook::visibleButtonCount() const
|
||||
return i;
|
||||
}
|
||||
|
||||
void Notebook::setTabVisibilityFilter(TabVisibilityFilter filter)
|
||||
{
|
||||
this->tabVisibilityFilter_ = std::move(filter);
|
||||
this->performLayout();
|
||||
this->updateTabVisibility();
|
||||
}
|
||||
|
||||
bool Notebook::shouldShowTab(const NotebookTab *tab) const
|
||||
{
|
||||
if (!this->showTabs_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->tabVisibilityFilter_)
|
||||
{
|
||||
return this->tabVisibilityFilter_(tab);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SplitNotebook::SplitNotebook(Window *parent)
|
||||
: Notebook(parent)
|
||||
{
|
||||
@@ -1061,6 +1197,24 @@ SplitNotebook::SplitNotebook(Window *parent)
|
||||
this->addCustomButtons();
|
||||
}
|
||||
|
||||
getSettings()->tabVisibility.connect(
|
||||
[this](int val, auto) {
|
||||
auto visibility = NotebookTabVisibility(val);
|
||||
switch (visibility)
|
||||
{
|
||||
case NotebookTabVisibility::LiveOnly:
|
||||
this->setTabVisibilityFilter([](const NotebookTab *tab) {
|
||||
return tab->isLive() || tab->isSelected();
|
||||
});
|
||||
break;
|
||||
case NotebookTabVisibility::AllTabs:
|
||||
default:
|
||||
this->setTabVisibilityFilter(nullptr);
|
||||
break;
|
||||
}
|
||||
},
|
||||
this->signalHolder_, true);
|
||||
|
||||
this->signalHolder_.managedConnect(
|
||||
getApp()->windows->selectSplit, [this](Split *split) {
|
||||
for (auto &&item : this->items())
|
||||
@@ -1204,7 +1358,6 @@ SplitContainer *SplitNotebook::addPage(bool select)
|
||||
auto tab = Notebook::addPage(container, QString(), select);
|
||||
container->setTab(tab);
|
||||
tab->setParent(this);
|
||||
tab->setVisible(this->getShowTabs());
|
||||
return container;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user