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: 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)
|
||||||
|
|
|
@ -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.",
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
};
|
};
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 "";
|
||||||
}},
|
}},
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 "
|
||||||
|
|
|
@ -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