diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b256671..0ffa81b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Minor: Added `/shoutout ` 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) diff --git a/src/controllers/hotkeys/ActionNames.hpp b/src/controllers/hotkeys/ActionNames.hpp index 58a2bb32..d658f05d 100644 --- a/src/controllers/hotkeys/ActionNames.hpp +++ b/src/controllers/hotkeys/ActionNames.hpp @@ -324,13 +324,18 @@ inline const std::map 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.", }}, }}, }; diff --git a/src/controllers/hotkeys/HotkeyController.cpp b/src/controllers/hotkeys/HotkeyController.cpp index df663975..16a1e035 100644 --- a/src/controllers/hotkeys/HotkeyController.cpp +++ b/src/controllers/hotkeys/HotkeyController.cpp @@ -500,6 +500,10 @@ void HotkeyController::addDefaults(std::set &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"); } } diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index 3d393a6a..dafa0dc6 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -126,6 +126,10 @@ public: EnumSetting tabDirection = {"/appearance/tabDirection", NotebookTabLocation::Top}; + EnumSetting tabVisibility = { + "/appearance/tabVisibility", + NotebookTabVisibility::AllTabs, + }; // BoolSetting collapseLongMessages = // {"/appearance/messages/collapseLongMessages", false}; diff --git a/src/widgets/Notebook.cpp b/src/widgets/Notebook.cpp index 40a9237a..89f1e202 100644 --- a/src/widgets/Notebook.cpp +++ b/src/widgets/Notebook.cpp @@ -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()}); - 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()}); + 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 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((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((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; } diff --git a/src/widgets/Notebook.hpp b/src/widgets/Notebook.hpp index 382b260e..eb41af63 100644 --- a/src/widgets/Notebook.hpp +++ b/src/widgets/Notebook.hpp @@ -9,6 +9,8 @@ #include #include +#include + 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; + 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 diff --git a/src/widgets/Window.cpp b/src/widgets/Window.cpp index efcd33d4..d3687281 100644 --- a/src/widgets/Window.cpp +++ b/src/widgets/Window.cpp @@ -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 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 ""; }}, }; diff --git a/src/widgets/dialogs/EmotePopup.cpp b/src/widgets/dialogs/EmotePopup.cpp index 8a096e27..2c4d9125 100644 --- a/src/widgets/dialogs/EmotePopup.cpp +++ b/src/widgets/dialogs/EmotePopup.cpp @@ -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 { diff --git a/src/widgets/helper/NotebookButton.cpp b/src/widgets/helper/NotebookButton.cpp index f6cc67b4..b7e8315a 100644 --- a/src/widgets/helper/NotebookButton.cpp +++ b/src/widgets/helper/NotebookButton.cpp @@ -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 diff --git a/src/widgets/helper/NotebookTab.cpp b/src/widgets/helper/NotebookTab.cpp index 539d4426..297ccf19 100644 --- a/src/widgets/helper/NotebookTab.cpp +++ b/src/widgets/helper/NotebookTab.cpp @@ -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) diff --git a/src/widgets/helper/NotebookTab.hpp b/src/widgets/helper/NotebookTab.hpp index 36d62262..dfc5b370 100644 --- a/src/widgets/helper/NotebookTab.hpp +++ b/src/widgets/helper/NotebookTab.hpp @@ -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; diff --git a/src/widgets/settingspages/GeneralPage.cpp b/src/widgets/settingspages/GeneralPage.cpp index 5bf6fe67..5c9ab87d 100644 --- a/src/widgets/settingspages/GeneralPage.cpp +++ b/src/widgets/settingspages/GeneralPage.cpp @@ -199,6 +199,30 @@ void GeneralPage::initLayout(GeneralPageView &layout) tabDirectionDropdown->setMinimumWidth( tabDirectionDropdown->minimumSizeHint().width()); + layout.addDropdown::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 " diff --git a/src/widgets/splits/SplitContainer.cpp b/src/widgets/splits/SplitContainer.cpp index d7de4740..43463f08 100644 --- a/src/widgets/splits/SplitContainer.cpp +++ b/src/widgets/splits/SplitContainer.cpp @@ -935,7 +935,14 @@ void SplitContainer::refreshTabLiveStatus() } } - this->tab_->setLive(liveStatus); + if (this->tab_->setLive(liveStatus)) + { + auto *notebook = dynamic_cast(this->parentWidget()); + if (notebook) + { + notebook->refresh(); + } + } } //