Add setting to only show tabs with live channels (#4358)

Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
Daniel Sage 2023-06-11 02:34:28 -07:00 committed by GitHub
parent c907f2b170
commit 4361790fbd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 412 additions and 136 deletions

View file

@ -7,6 +7,7 @@
- Minor: Added `/shoutout <username>` commands to shoutout specified user. (#4638) - Minor: Added `/shoutout <username>` commands to shoutout specified user. (#4638)
- Minor: Improved editing hotkeys. (#4628) - Minor: Improved editing hotkeys. (#4628)
- Minor: The input completion and quick switcher are now styled to match your theme. (#4671) - Minor: The input completion and quick switcher are now styled to match your theme. (#4671)
- Minor: Added setting to only show tabs with live channels (default toggle hotkey: Ctrl+Shift+L). (#4358)
- Bugfix: Fixed generation of crashdumps by the browser-extension process when the browser was closed. (#4667) - Bugfix: Fixed generation of crashdumps by the browser-extension process when the browser was closed. (#4667)
- Bugfix: Fix spacing issue with mentions inside RTL text. (#4677) - Bugfix: Fix spacing issue with mentions inside RTL text. (#4677)
- Bugfix: Fixed a crash when opening and closing a reply thread and switching the user. (#4675) - Bugfix: Fixed a crash when opening and closing a reply thread and switching the user. (#4675)

View file

@ -324,13 +324,18 @@ inline const std::map<HotkeyCategory, ActionDefinitionMap> actionNames{
{"setTabVisibility", {"setTabVisibility",
ActionDefinition{ ActionDefinition{
.displayName = "Set tab visibility", .displayName = "Set tab visibility",
.argumentDescription = "[on, off, or toggle. default: toggle]", .argumentDescription = "[on, off, toggle, liveOnly, or "
"toggleLiveOnly. default: toggle]",
.minCountArguments = 0, .minCountArguments = 0,
.maxCountArguments = 1, .maxCountArguments = 1,
.possibleArguments = HOTKEY_ARG_ON_OFF_TOGGLE, .possibleArguments{{"Toggle", {}},
{"Set to on", {"on"}},
{"Set to off", {"off"}},
{"Live only on", {"liveOnly"}},
{"Live only toggle", {"toggleLiveOnly"}}},
.argumentsPrompt = "New value:", .argumentsPrompt = "New value:",
.argumentsPromptHover = .argumentsPromptHover = "Should the tabs be enabled, disabled, "
"Should the tabs be enabled, disabled or toggled.", "toggled, or live-only.",
}}, }},
}}, }},
}; };

View file

@ -500,6 +500,10 @@ void HotkeyController::addDefaults(std::set<QString> &addedHotkeys)
this->tryAddDefault(addedHotkeys, HotkeyCategory::Window, this->tryAddDefault(addedHotkeys, HotkeyCategory::Window,
QKeySequence("Ctrl+U"), "setTabVisibility", QKeySequence("Ctrl+U"), "setTabVisibility",
{"toggle"}, "toggle tab visibility"); {"toggle"}, "toggle tab visibility");
this->tryAddDefault(addedHotkeys, HotkeyCategory::Window,
QKeySequence("Ctrl+Shift+L"), "setTabVisibility",
{"toggleLiveOnly"}, "toggle live tabs only");
} }
} }

View file

@ -126,6 +126,10 @@ public:
EnumSetting<NotebookTabLocation> tabDirection = {"/appearance/tabDirection", EnumSetting<NotebookTabLocation> tabDirection = {"/appearance/tabDirection",
NotebookTabLocation::Top}; NotebookTabLocation::Top};
EnumSetting<NotebookTabVisibility> tabVisibility = {
"/appearance/tabVisibility",
NotebookTabVisibility::AllTabs,
};
// BoolSetting collapseLongMessages = // BoolSetting collapseLongMessages =
// {"/appearance/messages/collapseLongMessages", false}; // {"/appearance/messages/collapseLongMessages", false};

View file

@ -92,9 +92,7 @@ NotebookTab *Notebook::addPage(QWidget *page, QString title, bool select)
} }
this->performLayout(); this->performLayout();
tab->setVisible(this->shouldShowTab(tab));
tab->show();
return tab; return tab;
} }
@ -216,6 +214,7 @@ void Notebook::select(QWidget *page, bool focusPage)
this->selectedPage_ = page; this->selectedPage_ = page;
this->performLayout(); this->performLayout();
this->updateTabVisibility();
} }
bool Notebook::containsPage(QWidget *page) bool Notebook::containsPage(QWidget *page)
@ -262,45 +261,121 @@ void Notebook::selectIndex(int index, bool focusPage)
this->select(this->items_[index].page, 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; return;
} }
auto index = int i = 0;
(this->indexOf(this->selectedPage_) + 1) % this->items_.count(); 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) 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; 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) void Notebook::selectLastTab(bool focusPage)
{ {
const auto size = this->items_.size(); if (!this->tabVisibilityFilter_)
if (size <= 1)
{ {
const auto size = this->items_.size();
if (size <= 1)
{
return;
}
this->select(this->items_[size - 1].page, focusPage);
return; 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 int Notebook::getPageCount() const
@ -329,6 +404,12 @@ QWidget *Notebook::tabAt(QPoint point, int &index, int maxWidth)
for (auto &item : this->items_) for (auto &item : this->items_)
{ {
if (!item.tab->isVisible())
{
i++;
continue;
}
auto rect = item.tab->getDesiredRect(); auto rect = item.tab->getDesiredRect();
rect.setHeight(int(this->scale() * 24)); rect.setHeight(int(this->scale() * 24));
@ -381,59 +462,73 @@ void Notebook::setShowTabs(bool value)
{ {
this->showTabs_ = value; this->showTabs_ = value;
this->performLayout();
for (auto &item : this->items_)
{
item.tab->setHidden(!value);
}
this->setShowAddButton(value); this->setShowAddButton(value);
this->performLayout();
this->updateTabVisibility();
this->updateTabVisibilityMenuAction();
// show a popup upon hiding tabs // show a popup upon hiding tabs
if (!value && getSettings()->informOnTabVisibilityToggle.getValue()) if (!value && getSettings()->informOnTabVisibilityToggle.getValue())
{ {
auto unhideSeq = getApp()->hotkeys->getDisplaySequence( this->showTabVisibilityInfoPopup();
HotkeyCategory::Window, "setTabVisibility", }
{std::vector<QString>()}); }
if (unhideSeq.isEmpty())
{ void Notebook::showTabVisibilityInfoPopup()
unhideSeq = getApp()->hotkeys->getDisplaySequence( {
HotkeyCategory::Window, "setTabVisibility", {{"toggle"}}); auto unhideSeq = getApp()->hotkeys->getDisplaySequence(
} HotkeyCategory::Window, "setTabVisibility", {std::vector<QString>()});
if (unhideSeq.isEmpty()) if (unhideSeq.isEmpty())
{ {
unhideSeq = getApp()->hotkeys->getDisplaySequence( unhideSeq = getApp()->hotkeys->getDisplaySequence(
HotkeyCategory::Window, "setTabVisibility", {{"on"}}); HotkeyCategory::Window, "setTabVisibility", {{"toggle"}});
} }
QString hotkeyInfo = "(currently unbound)"; if (unhideSeq.isEmpty())
if (!unhideSeq.isEmpty()) {
{ unhideSeq = getApp()->hotkeys->getDisplaySequence(
hotkeyInfo = HotkeyCategory::Window, "setTabVisibility", {{"on"}});
"(" + }
unhideSeq.toString(QKeySequence::SequenceFormat::NativeText) + QString hotkeyInfo = "(currently unbound)";
")"; if (!unhideSeq.isEmpty())
} {
QMessageBox msgBox(this->window()); hotkeyInfo =
msgBox.window()->setWindowTitle("Chatterino - hidden tabs"); "(" + unhideSeq.toString(QKeySequence::SequenceFormat::NativeText) +
msgBox.setText("You've just hidden your tabs."); ")";
msgBox.setInformativeText( }
"You can toggle tabs by using the keyboard shortcut " + hotkeyInfo + QMessageBox msgBox(this->window());
" or right-clicking the tab area and selecting \"Toggle " msgBox.window()->setWindowTitle("Chatterino - hidden tabs");
"visibility of tabs\"."); msgBox.setText("You've just hidden your tabs.");
msgBox.addButton(QMessageBox::Ok); msgBox.setInformativeText(
auto *dsaButton = "You can toggle tabs by using the keyboard shortcut " + hotkeyInfo +
msgBox.addButton("Don't show again", QMessageBox::YesRole); " or right-clicking the tab area and selecting \"Toggle "
"visibility of tabs\".");
msgBox.setDefaultButton(QMessageBox::Ok); msgBox.addButton(QMessageBox::Ok);
auto *dsaButton =
msgBox.exec(); msgBox.addButton("Don't show again", QMessageBox::YesRole);
if (msgBox.clickedButton() == dsaButton) msgBox.setDefaultButton(QMessageBox::Ok);
{
getSettings()->informOnTabVisibilityToggle.setValue(false); 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() void Notebook::updateTabVisibilityMenuAction()
@ -510,6 +605,21 @@ void Notebook::performLayout(bool animated)
const auto buttonWidth = tabHeight; const auto buttonWidth = tabHeight;
const auto buttonHeight = tabHeight - 1; 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) if (this->tabLocation_ == NotebookTabLocation::Top)
{ {
auto x = left; auto x = left;
@ -535,14 +645,14 @@ void Notebook::performLayout(bool animated)
{ {
// layout tabs // layout tabs
/// Notebook tabs need to know if they are in the last row. /// Notebook tabs need to know if they are in the last row.
auto firstInBottomRow = auto *firstInBottomRow =
this->items_.size() ? &this->items_.front() : nullptr; filteredItems.empty() ? nullptr : &filteredItems.front();
for (auto &item : this->items_) for (auto &item : filteredItems)
{ {
/// Break line if element doesn't fit. /// Break line if element doesn't fit.
auto isFirst = &item == &this->items_.front(); auto isFirst = &item == &filteredItems.front();
auto isLast = &item == &this->items_.back(); auto isLast = &item == &filteredItems.back();
auto fitsInLine = ((isLast ? addButtonWidth : 0) + x + auto fitsInLine = ((isLast ? addButtonWidth : 0) + x +
item.tab->width()) <= width(); item.tab->width()) <= width();
@ -562,7 +672,7 @@ void Notebook::performLayout(bool animated)
/// Update which tabs are in the last row /// Update which tabs are in the last row
auto inLastRow = false; auto inLastRow = false;
for (const auto &item : this->items_) for (const auto &item : filteredItems)
{ {
if (&item == firstInBottomRow) if (&item == firstInBottomRow)
{ {
@ -633,7 +743,7 @@ void Notebook::performLayout(bool animated)
{ {
return; return;
} }
int count = this->items_.size() + (this->showAddButton_ ? 1 : 0); int count = filteredItems.size() + (this->showAddButton_ ? 1 : 0);
int columnCount = ceil((float)count / tabsPerColumn); int columnCount = ceil((float)count / tabsPerColumn);
// only add width of all the tabs if they are not hidden // 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; bool isLastColumn = col == columnCount - 1;
auto largestWidth = 0; auto largestWidth = 0;
int tabStart = col * tabsPerColumn; int tabStart = col * tabsPerColumn;
int tabEnd = std::min((col + 1) * tabsPerColumn, int tabEnd =
(int)this->items_.size()); std::min(static_cast<size_t>((col + 1) * tabsPerColumn),
filteredItems.size());
for (int i = tabStart; i < tabEnd; i++) for (int i = tabStart; i < tabEnd; i++)
{ {
largestWidth = std::max( largestWidth =
this->items_.at(i).tab->normalTabWidth(), largestWidth); std::max(filteredItems.at(i).tab->normalTabWidth(),
largestWidth);
} }
if (isLastColumn && this->showAddButton_) if (isLastColumn && this->showAddButton_)
@ -664,7 +776,7 @@ void Notebook::performLayout(bool animated)
for (int i = tabStart; i < tabEnd; i++) for (int i = tabStart; i < tabEnd; i++)
{ {
auto item = this->items_.at(i); auto item = filteredItems.at(i);
/// Layout tab /// Layout tab
item.tab->growWidth(largestWidth); item.tab->growWidth(largestWidth);
@ -735,7 +847,7 @@ void Notebook::performLayout(bool animated)
{ {
return; return;
} }
int count = this->items_.size() + (this->showAddButton_ ? 1 : 0); int count = filteredItems.size() + (this->showAddButton_ ? 1 : 0);
int columnCount = ceil((float)count / tabsPerColumn); int columnCount = ceil((float)count / tabsPerColumn);
// only add width of all the tabs if they are not hidden // 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; bool isLastColumn = col == columnCount - 1;
auto largestWidth = 0; auto largestWidth = 0;
int tabStart = col * tabsPerColumn; int tabStart = col * tabsPerColumn;
int tabEnd = std::min((col + 1) * tabsPerColumn, int tabEnd =
(int)this->items_.size()); std::min(static_cast<size_t>((col + 1) * tabsPerColumn),
filteredItems.size());
for (int i = tabStart; i < tabEnd; i++) for (int i = tabStart; i < tabEnd; i++)
{ {
largestWidth = std::max( largestWidth =
this->items_.at(i).tab->normalTabWidth(), largestWidth); std::max(filteredItems.at(i).tab->normalTabWidth(),
largestWidth);
} }
if (isLastColumn && this->showAddButton_) if (isLastColumn && this->showAddButton_)
@ -771,7 +885,7 @@ void Notebook::performLayout(bool animated)
for (int i = tabStart; i < tabEnd; i++) for (int i = tabStart; i < tabEnd; i++)
{ {
auto item = this->items_.at(i); auto item = filteredItems.at(i);
/// Layout tab /// Layout tab
item.tab->growWidth(largestWidth); item.tab->growWidth(largestWidth);
@ -840,14 +954,14 @@ void Notebook::performLayout(bool animated)
// layout tabs // layout tabs
/// Notebook tabs need to know if they are in the last row. /// Notebook tabs need to know if they are in the last row.
auto firstInBottomRow = auto *firstInBottomRow =
this->items_.size() ? &this->items_.front() : nullptr; filteredItems.empty() ? nullptr : &filteredItems.front();
for (auto &item : this->items_) for (auto &item : filteredItems)
{ {
/// Break line if element doesn't fit. /// Break line if element doesn't fit.
auto isFirst = &item == &this->items_.front(); auto isFirst = &item == &filteredItems.front();
auto isLast = &item == &this->items_.back(); auto isLast = &item == &filteredItems.back();
auto fitsInLine = ((isLast ? addButtonWidth : 0) + x + auto fitsInLine = ((isLast ? addButtonWidth : 0) + x +
item.tab->width()) <= width(); item.tab->width()) <= width();
@ -867,7 +981,7 @@ void Notebook::performLayout(bool animated)
/// Update which tabs are in the last row /// Update which tabs are in the last row
auto inLastRow = false; auto inLastRow = false;
for (const auto &item : this->items_) for (const auto &item : filteredItems)
{ {
if (&item == firstInBottomRow) if (&item == firstInBottomRow)
{ {
@ -1046,6 +1160,28 @@ size_t Notebook::visibleButtonCount() const
return i; 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) SplitNotebook::SplitNotebook(Window *parent)
: Notebook(parent) : Notebook(parent)
{ {
@ -1061,6 +1197,24 @@ SplitNotebook::SplitNotebook(Window *parent)
this->addCustomButtons(); 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( this->signalHolder_.managedConnect(
getApp()->windows->selectSplit, [this](Split *split) { getApp()->windows->selectSplit, [this](Split *split) {
for (auto &&item : this->items()) for (auto &&item : this->items())
@ -1204,7 +1358,6 @@ SplitContainer *SplitNotebook::addPage(bool select)
auto tab = Notebook::addPage(container, QString(), select); auto tab = Notebook::addPage(container, QString(), select);
container->setTab(tab); container->setTab(tab);
tab->setParent(this); tab->setParent(this);
tab->setVisible(this->getShowTabs());
return container; return container;
} }

View file

@ -9,6 +9,8 @@
#include <QMessageBox> #include <QMessageBox>
#include <QWidget> #include <QWidget>
#include <functional>
namespace chatterino { namespace chatterino {
class Window; class Window;
@ -19,6 +21,17 @@ class SplitContainer;
enum NotebookTabLocation { Top = 0, Left = 1, Right = 2, Bottom = 3 }; enum NotebookTabLocation { Top = 0, Left = 1, Right = 2, Bottom = 3 };
// Controls the visibility of tabs in this notebook
enum NotebookTabVisibility : int {
// Show all tabs
AllTabs = 0,
// Only show tabs containing splits that are live
LiveOnly = 1,
};
using TabVisibilityFilter = std::function<bool(const NotebookTab *)>;
class Notebook : public BaseWidget class Notebook : public BaseWidget
{ {
Q_OBJECT Q_OBJECT
@ -35,6 +48,7 @@ public:
int indexOf(QWidget *page) const; int indexOf(QWidget *page) const;
virtual void select(QWidget *page, bool focusPage = true); virtual void select(QWidget *page, bool focusPage = true);
void selectIndex(int index, bool focusPage = true); void selectIndex(int index, bool focusPage = true);
void selectVisibleIndex(int index, bool focusPage = true);
void selectNextTab(bool focusPage = true); void selectNextTab(bool focusPage = true);
void selectPreviousTab(bool focusPage = true); void selectPreviousTab(bool focusPage = true);
void selectLastTab(bool focusPage = true); void selectLastTab(bool focusPage = true);
@ -56,8 +70,6 @@ public:
bool getShowAddButton() const; bool getShowAddButton() const;
void setShowAddButton(bool value); void setShowAddButton(bool value);
void performLayout(bool animate = false);
void setTabLocation(NotebookTabLocation location); void setTabLocation(NotebookTabLocation location);
bool isNotebookLayoutLocked() const; bool isNotebookLayoutLocked() const;
@ -65,6 +77,9 @@ public:
void addNotebookActionsToMenu(QMenu *menu); void addNotebookActionsToMenu(QMenu *menu);
// Update layout and tab visibility
void refresh();
protected: protected:
virtual void scaleChangedEvent(float scale_) override; virtual void scaleChangedEvent(float scale_) override;
virtual void resizeEvent(QResizeEvent *) override; virtual void resizeEvent(QResizeEvent *) override;
@ -85,7 +100,32 @@ protected:
return items_; return items_;
} }
/**
* @brief Apply the given tab visibility filter
*
* An empty function can be provided to denote that no filter will be applied
*
* Tabs will be redrawn after this function is called.
**/
void setTabVisibilityFilter(TabVisibilityFilter filter);
/**
* @brief shouldShowTab has the final say whether a tab should be visible right now.
**/
bool shouldShowTab(const NotebookTab *tab) const;
private: private:
void performLayout(bool animate = false);
/**
* @brief Show a popup informing the user of some big tab visibility changes
**/
void showTabVisibilityInfoPopup();
/**
* @brief Updates the visibility state of all tabs
**/
void updateTabVisibility();
void updateTabVisibilityMenuAction(); void updateTabVisibilityMenuAction();
void resizeAddButton(); void resizeAddButton();
@ -113,6 +153,10 @@ private:
NotebookTabLocation tabLocation_ = NotebookTabLocation::Top; NotebookTabLocation tabLocation_ = NotebookTabLocation::Top;
QAction *lockNotebookLayoutAction_; QAction *lockNotebookLayoutAction_;
QAction *showTabsAction_; QAction *showTabsAction_;
// This filter, if set, is used to figure out the visibility of
// the tabs in this notebook.
TabVisibilityFilter tabVisibilityFilter_;
}; };
class SplitNotebook : public Notebook class SplitNotebook : public Notebook

View file

@ -354,7 +354,7 @@ void Window::addShortcuts()
int result = target.toInt(&ok); int result = target.toInt(&ok);
if (ok) if (ok)
{ {
this->notebook_->selectIndex(result); this->notebook_->selectVisibleIndex(result);
} }
else else
{ {
@ -619,46 +619,61 @@ void Window::addShortcuts()
}}, }},
{"setTabVisibility", {"setTabVisibility",
[this](std::vector<QString> arguments) -> QString { [this](std::vector<QString> arguments) -> QString {
auto mode = 2; QString arg = arguments.empty() ? "toggle" : arguments.front();
if (arguments.size() != 0)
if (arg == "off")
{ {
auto arg = arguments.at(0); this->notebook_->setShowTabs(false);
if (arg == "off") getSettings()->tabVisibility.setValue(
NotebookTabVisibility::AllTabs);
}
else if (arg == "on")
{
this->notebook_->setShowTabs(true);
getSettings()->tabVisibility.setValue(
NotebookTabVisibility::AllTabs);
}
else if (arg == "toggle")
{
this->notebook_->setShowTabs(!this->notebook_->getShowTabs());
getSettings()->tabVisibility.setValue(
NotebookTabVisibility::AllTabs);
}
else if (arg == "liveOnly")
{
this->notebook_->setShowTabs(true);
getSettings()->tabVisibility.setValue(
NotebookTabVisibility::LiveOnly);
}
else if (arg == "toggleLiveOnly")
{
if (!this->notebook_->getShowTabs())
{ {
mode = 0; // Tabs are currently hidden, so the intention is to show
} // tabs again before enabling the live only setting
else if (arg == "on") this->notebook_->setShowTabs(true);
{ getSettings()->tabVisibility.setValue(
mode = 1; NotebookTabVisibility::LiveOnly);
}
else if (arg == "toggle")
{
mode = 2;
} }
else else
{ {
qCWarning(chatterinoHotkeys) getSettings()->tabVisibility.setValue(
<< "Invalid argument for setStreamerMode hotkey: " getSettings()->tabVisibility.getEnum() ==
<< arg; NotebookTabVisibility::LiveOnly
return QString("Invalid argument for setTabVisibility " ? NotebookTabVisibility::AllTabs
"hotkey: %1. Use \"on\", \"off\" or " : NotebookTabVisibility::LiveOnly);
"\"toggle\".")
.arg(arg);
} }
} }
else
{
qCWarning(chatterinoHotkeys)
<< "Invalid argument for setTabVisibility hotkey: " << arg;
return QString("Invalid argument for setTabVisibility hotkey: "
"%1. Use \"on\", \"off\", \"toggle\", "
"\"liveOnly\", or \"toggleLiveOnly\".")
.arg(arg);
}
if (mode == 0)
{
this->notebook_->setShowTabs(false);
}
else if (mode == 1)
{
this->notebook_->setShowTabs(true);
}
else if (mode == 2)
{
this->notebook_->setShowTabs(!this->notebook_->getShowTabs());
}
return ""; return "";
}}, }},
}; };

View file

@ -310,7 +310,7 @@ void EmotePopup::addShortcuts()
int result = target.toInt(&ok); int result = target.toInt(&ok);
if (ok) if (ok)
{ {
this->notebook_->selectIndex(result, false); this->notebook_->selectVisibleIndex(result, false);
} }
else else
{ {

View file

@ -211,12 +211,12 @@ void NotebookButton::dropEvent(QDropEvent *event)
void NotebookButton::hideEvent(QHideEvent *) void NotebookButton::hideEvent(QHideEvent *)
{ {
this->parent_->performLayout(); this->parent_->refresh();
} }
void NotebookButton::showEvent(QShowEvent *) void NotebookButton::showEvent(QShowEvent *)
{ {
this->parent_->performLayout(); this->parent_->refresh();
} }
} // namespace chatterino } // namespace chatterino

View file

@ -234,7 +234,7 @@ void NotebookTab::updateSize()
if (this->width() != width || this->height() != height) if (this->width() != width || this->height() != height)
{ {
this->resize(width, height); this->resize(width, height);
this->notebook_->performLayout(); this->notebook_->refresh();
} }
} }
@ -290,7 +290,7 @@ void NotebookTab::titleUpdated()
{ {
// Queue up save because: Tab title changed // Queue up save because: Tab title changed
getApp()->windows->queueSave(); getApp()->windows->queueSave();
this->notebook_->performLayout(); this->notebook_->refresh();
this->updateSize(); this->updateSize();
this->update(); this->update();
} }
@ -327,13 +327,21 @@ void NotebookTab::setTabLocation(NotebookTabLocation location)
} }
} }
void NotebookTab::setLive(bool isLive) bool NotebookTab::setLive(bool isLive)
{ {
if (this->isLive_ != isLive) if (this->isLive_ != isLive)
{ {
this->isLive_ = isLive; this->isLive_ = isLive;
this->update(); this->update();
return true;
} }
return false;
}
bool NotebookTab::isLive() const
{
return this->isLive_;
} }
void NotebookTab::setHighlightState(HighlightState newHighlightStyle) void NotebookTab::setHighlightState(HighlightState newHighlightStyle)

View file

@ -40,7 +40,18 @@ public:
void setInLastRow(bool value); void setInLastRow(bool value);
void setTabLocation(NotebookTabLocation location); void setTabLocation(NotebookTabLocation location);
void setLive(bool isLive); /**
* @brief Sets the live status of this tab
*
* Returns true if the live status was changed, false if nothing changed.
**/
bool setLive(bool isLive);
/**
* @brief Returns true if any split in this tab is live
**/
bool isLive() const;
void setHighlightState(HighlightState style); void setHighlightState(HighlightState style);
void setHighlightsEnabled(const bool &newVal); void setHighlightsEnabled(const bool &newVal);
bool hasHighlightsEnabled() const; bool hasHighlightsEnabled() const;

View file

@ -199,6 +199,30 @@ void GeneralPage::initLayout(GeneralPageView &layout)
tabDirectionDropdown->setMinimumWidth( tabDirectionDropdown->setMinimumWidth(
tabDirectionDropdown->minimumSizeHint().width()); tabDirectionDropdown->minimumSizeHint().width());
layout.addDropdown<std::underlying_type<NotebookTabVisibility>::type>(
"Tab visibility", {"All tabs", "Only live tabs"}, s.tabVisibility,
[](auto val) {
switch (val)
{
case NotebookTabVisibility::LiveOnly:
return "Only live tabs";
case NotebookTabVisibility::AllTabs:
default:
return "All tabs";
}
},
[](auto args) {
if (args.value == "Only live tabs")
{
return NotebookTabVisibility::LiveOnly;
}
else
{
return NotebookTabVisibility::AllTabs;
}
},
false, "Choose which tabs are visible in the notebook");
layout.addCheckbox( layout.addCheckbox(
"Show message reply context", s.hideReplyContext, true, "Show message reply context", s.hideReplyContext, true,
"This setting will only affect how messages are shown. You can reply " "This setting will only affect how messages are shown. You can reply "

View file

@ -935,7 +935,14 @@ void SplitContainer::refreshTabLiveStatus()
} }
} }
this->tab_->setLive(liveStatus); if (this->tab_->setLive(liveStatus))
{
auto *notebook = dynamic_cast<Notebook *>(this->parentWidget());
if (notebook)
{
notebook->refresh();
}
}
} }
// //