mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
Add setting to only show tabs with live channels (#4358)
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
parent
c907f2b170
commit
4361790fbd
|
@ -7,6 +7,7 @@
|
|||
- Minor: Added `/shoutout <username>` commands to shoutout specified user. (#4638)
|
||||
- Minor: Improved editing hotkeys. (#4628)
|
||||
- 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: 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)
|
||||
|
|
|
@ -324,13 +324,18 @@ inline const std::map<HotkeyCategory, ActionDefinitionMap> actionNames{
|
|||
{"setTabVisibility",
|
||||
ActionDefinition{
|
||||
.displayName = "Set tab visibility",
|
||||
.argumentDescription = "[on, off, or toggle. default: toggle]",
|
||||
.argumentDescription = "[on, off, toggle, liveOnly, or "
|
||||
"toggleLiveOnly. default: toggle]",
|
||||
.minCountArguments = 0,
|
||||
.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:",
|
||||
.argumentsPromptHover =
|
||||
"Should the tabs be enabled, disabled or toggled.",
|
||||
.argumentsPromptHover = "Should the tabs be enabled, disabled, "
|
||||
"toggled, or live-only.",
|
||||
}},
|
||||
}},
|
||||
};
|
||||
|
|
|
@ -500,6 +500,10 @@ void HotkeyController::addDefaults(std::set<QString> &addedHotkeys)
|
|||
this->tryAddDefault(addedHotkeys, HotkeyCategory::Window,
|
||||
QKeySequence("Ctrl+U"), "setTabVisibility",
|
||||
{"toggle"}, "toggle tab visibility");
|
||||
|
||||
this->tryAddDefault(addedHotkeys, HotkeyCategory::Window,
|
||||
QKeySequence("Ctrl+Shift+L"), "setTabVisibility",
|
||||
{"toggleLiveOnly"}, "toggle live tabs only");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -126,6 +126,10 @@ public:
|
|||
|
||||
EnumSetting<NotebookTabLocation> tabDirection = {"/appearance/tabDirection",
|
||||
NotebookTabLocation::Top};
|
||||
EnumSetting<NotebookTabVisibility> tabVisibility = {
|
||||
"/appearance/tabVisibility",
|
||||
NotebookTabVisibility::AllTabs,
|
||||
};
|
||||
|
||||
// BoolSetting collapseLongMessages =
|
||||
// {"/appearance/messages/collapseLongMessages", false};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <QMessageBox>
|
||||
#include <QWidget>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class Window;
|
||||
|
@ -19,6 +21,17 @@ class SplitContainer;
|
|||
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -35,6 +48,7 @@ public:
|
|||
int indexOf(QWidget *page) const;
|
||||
virtual void select(QWidget *page, bool focusPage = true);
|
||||
void selectIndex(int index, bool focusPage = true);
|
||||
void selectVisibleIndex(int index, bool focusPage = true);
|
||||
void selectNextTab(bool focusPage = true);
|
||||
void selectPreviousTab(bool focusPage = true);
|
||||
void selectLastTab(bool focusPage = true);
|
||||
|
@ -56,8 +70,6 @@ public:
|
|||
bool getShowAddButton() const;
|
||||
void setShowAddButton(bool value);
|
||||
|
||||
void performLayout(bool animate = false);
|
||||
|
||||
void setTabLocation(NotebookTabLocation location);
|
||||
|
||||
bool isNotebookLayoutLocked() const;
|
||||
|
@ -65,6 +77,9 @@ public:
|
|||
|
||||
void addNotebookActionsToMenu(QMenu *menu);
|
||||
|
||||
// Update layout and tab visibility
|
||||
void refresh();
|
||||
|
||||
protected:
|
||||
virtual void scaleChangedEvent(float scale_) override;
|
||||
virtual void resizeEvent(QResizeEvent *) override;
|
||||
|
@ -85,7 +100,32 @@ protected:
|
|||
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:
|
||||
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 resizeAddButton();
|
||||
|
||||
|
@ -113,6 +153,10 @@ private:
|
|||
NotebookTabLocation tabLocation_ = NotebookTabLocation::Top;
|
||||
QAction *lockNotebookLayoutAction_;
|
||||
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
|
||||
|
|
|
@ -354,7 +354,7 @@ void Window::addShortcuts()
|
|||
int result = target.toInt(&ok);
|
||||
if (ok)
|
||||
{
|
||||
this->notebook_->selectIndex(result);
|
||||
this->notebook_->selectVisibleIndex(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -619,46 +619,61 @@ void Window::addShortcuts()
|
|||
}},
|
||||
{"setTabVisibility",
|
||||
[this](std::vector<QString> arguments) -> QString {
|
||||
auto mode = 2;
|
||||
if (arguments.size() != 0)
|
||||
QString arg = arguments.empty() ? "toggle" : arguments.front();
|
||||
|
||||
if (arg == "off")
|
||||
{
|
||||
auto arg = arguments.at(0);
|
||||
if (arg == "off")
|
||||
this->notebook_->setShowTabs(false);
|
||||
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;
|
||||
}
|
||||
else if (arg == "on")
|
||||
{
|
||||
mode = 1;
|
||||
}
|
||||
else if (arg == "toggle")
|
||||
{
|
||||
mode = 2;
|
||||
// Tabs are currently hidden, so the intention is to show
|
||||
// tabs again before enabling the live only setting
|
||||
this->notebook_->setShowTabs(true);
|
||||
getSettings()->tabVisibility.setValue(
|
||||
NotebookTabVisibility::LiveOnly);
|
||||
}
|
||||
else
|
||||
{
|
||||
qCWarning(chatterinoHotkeys)
|
||||
<< "Invalid argument for setStreamerMode hotkey: "
|
||||
<< arg;
|
||||
return QString("Invalid argument for setTabVisibility "
|
||||
"hotkey: %1. Use \"on\", \"off\" or "
|
||||
"\"toggle\".")
|
||||
.arg(arg);
|
||||
getSettings()->tabVisibility.setValue(
|
||||
getSettings()->tabVisibility.getEnum() ==
|
||||
NotebookTabVisibility::LiveOnly
|
||||
? NotebookTabVisibility::AllTabs
|
||||
: NotebookTabVisibility::LiveOnly);
|
||||
}
|
||||
}
|
||||
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 "";
|
||||
}},
|
||||
};
|
||||
|
|
|
@ -310,7 +310,7 @@ void EmotePopup::addShortcuts()
|
|||
int result = target.toInt(&ok);
|
||||
if (ok)
|
||||
{
|
||||
this->notebook_->selectIndex(result, false);
|
||||
this->notebook_->selectVisibleIndex(result, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -211,12 +211,12 @@ void NotebookButton::dropEvent(QDropEvent *event)
|
|||
|
||||
void NotebookButton::hideEvent(QHideEvent *)
|
||||
{
|
||||
this->parent_->performLayout();
|
||||
this->parent_->refresh();
|
||||
}
|
||||
|
||||
void NotebookButton::showEvent(QShowEvent *)
|
||||
{
|
||||
this->parent_->performLayout();
|
||||
this->parent_->refresh();
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -234,7 +234,7 @@ void NotebookTab::updateSize()
|
|||
if (this->width() != width || this->height() != 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
|
||||
getApp()->windows->queueSave();
|
||||
this->notebook_->performLayout();
|
||||
this->notebook_->refresh();
|
||||
this->updateSize();
|
||||
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)
|
||||
{
|
||||
this->isLive_ = isLive;
|
||||
this->update();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NotebookTab::isLive() const
|
||||
{
|
||||
return this->isLive_;
|
||||
}
|
||||
|
||||
void NotebookTab::setHighlightState(HighlightState newHighlightStyle)
|
||||
|
|
|
@ -40,7 +40,18 @@ public:
|
|||
void setInLastRow(bool value);
|
||||
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 setHighlightsEnabled(const bool &newVal);
|
||||
bool hasHighlightsEnabled() const;
|
||||
|
|
|
@ -199,6 +199,30 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
|||
tabDirectionDropdown->setMinimumWidth(
|
||||
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(
|
||||
"Show message reply context", s.hideReplyContext, true,
|
||||
"This setting will only affect how messages are shown. You can reply "
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
Loading…
Reference in a new issue