From 57354283ec373f06920e41effe954d3333ca52f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82?= Date: Sun, 30 May 2021 13:39:34 +0200 Subject: [PATCH] Added ability to toggle visibility of tabs (#2600) This can be done by right-clicking the tab area or pressing the keyboard shortcut (default: Ctrl+U). Co-authored-by: Leon Richardt Co-authored-by: Rasmus Karlsson --- CHANGELOG.md | 1 + src/singletons/Settings.hpp | 2 + src/widgets/Notebook.cpp | 254 ++++++++++++------ src/widgets/Notebook.hpp | 7 + src/widgets/Window.cpp | 4 + src/widgets/helper/NotebookTab.cpp | 6 + .../settingspages/KeyboardSettingsPage.cpp | 1 + 7 files changed, 188 insertions(+), 87 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b2a3494d..29a30b613 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unversioned +- Major: Added ability to toggle visibility of Channel Tabs - This can be done by right-clicking the tab area or pressing the keyboard shortcut (default: Ctrl+U). (#2600) - Minor: Added moderation buttons to search popup when searching in a split with moderation mode enabled. (#2148, #2803) - Minor: Made "#channel" in `/mentions` tab show in usercards and in the search popup. (#2802) - Minor: Added settings to disable custom FrankerFaceZ VIP/mod badges. (#2693, #2759) diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index 25ab4a835..e53599d38 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -360,6 +360,8 @@ public: BoolSetting attachExtensionToAnyProcess = { "/misc/attachExtensionToAnyProcess", false}; BoolSetting askOnImageUpload = {"/misc/askOnImageUpload", true}; + BoolSetting informOnTabVisibilityToggle = {"/misc/askOnTabVisibilityToggle", + true}; /// Debug BoolSetting showUnhandledIrcMessages = {"/debug/showUnhandledIrcMessages", diff --git a/src/widgets/Notebook.cpp b/src/widgets/Notebook.cpp index a3663a2d5..0d551e147 100644 --- a/src/widgets/Notebook.cpp +++ b/src/widgets/Notebook.cpp @@ -29,11 +29,16 @@ namespace chatterino { Notebook::Notebook(QWidget *parent) : BaseWidget(parent) + , menu_(this) , addButton_(new NotebookButton(this)) { this->addButton_->setIcon(NotebookButton::Icon::Plus); this->addButton_->setHidden(true); + + this->menu_.addAction("Toggle visibility of tabs", [this]() { + this->setShowTabs(!this->getShowTabs()); + }); } NotebookTab *Notebook::addPage(QWidget *page, QString title, bool select) @@ -325,6 +330,48 @@ void Notebook::setAllowUserTabManagement(bool value) this->allowUserTabManagement_ = value; } +bool Notebook::getShowTabs() const +{ + return this->showTabs_; +} + +void Notebook::setShowTabs(bool value) +{ + this->showTabs_ = value; + + this->performLayout(); + for (auto &item : this->items_) + { + item.tab->setHidden(!value); + } + + this->setShowAddButton(value); + + // show a popup upon hiding tabs + if (!value && getSettings()->informOnTabVisibilityToggle.getValue()) + { + QMessageBox msgBox; + 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 (Ctrl + U by " + "default) or right-clicking on 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); + } + } +} + bool Notebook::getShowAddButton() const { return this->showAddButton_; @@ -359,12 +406,14 @@ void Notebook::performLayout(bool animated) const auto left = int(2 * this->scale()); const auto scale = this->scale(); const auto tabHeight = int(NOTEBOOK_TAB_HEIGHT * scale); + const auto minimumTabAreaSpace = int(tabHeight * 0.5); const auto addButtonWidth = this->showAddButton_ ? tabHeight : 0; if (this->tabDirection_ == NotebookTabDirection::Horizontal) { auto x = left; auto y = 0; + auto buttonHeight = 0; // set size of custom buttons (settings, user, ...) for (auto *btn : this->customButtons_) @@ -377,77 +426,86 @@ void Notebook::performLayout(bool animated) btn->setFixedSize(tabHeight, tabHeight - 1); btn->move(x, 0); x += tabHeight; + + buttonHeight = tabHeight; } - // layout tabs - /// Notebook tabs need to know if they are in the last row. - auto firstInBottomRow = - this->items_.size() ? &this->items_.front() : nullptr; - - for (auto &item : this->items_) + if (this->showTabs_) { - /// Break line if element doesn't fit. - auto isFirst = &item == &this->items_.front(); - auto isLast = &item == &this->items_.back(); + // layout tabs + /// Notebook tabs need to know if they are in the last row. + auto firstInBottomRow = + this->items_.size() ? &this->items_.front() : nullptr; - auto fitsInLine = ((isLast ? addButtonWidth : 0) + x + - item.tab->width()) <= width(); - - if (!isFirst && !fitsInLine) + for (auto &item : this->items_) { - y += item.tab->height(); - x = left; - firstInBottomRow = &item; + /// Break line if element doesn't fit. + auto isFirst = &item == &this->items_.front(); + auto isLast = &item == &this->items_.back(); + + auto fitsInLine = ((isLast ? addButtonWidth : 0) + x + + item.tab->width()) <= width(); + + if (!isFirst && !fitsInLine) + { + y += item.tab->height(); + x = left; + firstInBottomRow = &item; + } + + /// Layout tab + item.tab->growWidth(0); + item.tab->moveAnimated(QPoint(x, y), animated); + x += item.tab->width() + std::max(1, int(scale * 1)); } - /// Layout tab - item.tab->growWidth(0); - item.tab->moveAnimated(QPoint(x, y), animated); - x += item.tab->width() + std::max(1, int(scale * 1)); - } - - /// Update which tabs are in the last row - auto inLastRow = false; - for (const auto &item : this->items_) - { - if (&item == firstInBottomRow) + /// Update which tabs are in the last row + auto inLastRow = false; + for (const auto &item : this->items_) { - inLastRow = true; + if (&item == firstInBottomRow) + { + inLastRow = true; + } + item.tab->setInLastRow(inLastRow); + } + + // move misc buttons + if (this->showAddButton_) + { + this->addButton_->move(x, y); + } + + y += tabHeight; + + // raise elements + for (auto &i : this->items_) + { + i.tab->raise(); + } + + if (this->showAddButton_) + { + this->addButton_->raise(); } - item.tab->setInLastRow(inLastRow); } - // move misc buttons - if (this->showAddButton_) - { - this->addButton_->move(x, y); - } + y = std::max({y, buttonHeight, minimumTabAreaSpace}); - if (this->lineOffset_ != y + tabHeight) + if (this->lineOffset_ != y) { - this->lineOffset_ = y + tabHeight; + this->lineOffset_ = y; this->update(); } /// Increment for the line at the bottom y += int(2 * scale); - // raise elements - for (auto &i : this->items_) - { - i.tab->raise(); - } - - if (this->showAddButton_) - { - this->addButton_->raise(); - } - // set page bounds if (this->selectedPage_ != nullptr) { - this->selectedPage_->move(0, y + tabHeight); - this->selectedPage_->resize(width(), height() - y - tabHeight); + this->selectedPage_->move(0, y); + this->selectedPage_->resize(width(), height() - y); this->selectedPage_->raise(); } } @@ -477,54 +535,62 @@ void Notebook::performLayout(bool animated) int top = y; x = left; + // zneix: if we were to remove buttons when tabs are hidden + // stuff below to "set page bounds" part should be in conditional statement int verticalRowSpace = (this->height() - top) / tabHeight; if (verticalRowSpace == 0) // window hasn't properly rendered yet + { return; + } int count = this->items_.size() + (this->showAddButton_ ? 1 : 0); int columnCount = ceil((float)count / verticalRowSpace); - for (int col = 0; col < columnCount; col++) + // only add width of all the tabs if they are not hidden + if (this->showTabs_) { - auto largestWidth = 0; - int colStart = col * verticalRowSpace; - int colEnd = - std::min((col + 1) * verticalRowSpace, this->items_.size()); - - for (int i = colStart; i < colEnd; i++) + for (int col = 0; col < columnCount; col++) { - largestWidth = std::max( - this->items_.at(i).tab->normalTabWidth(), largestWidth); + auto largestWidth = 0; + int colStart = col * verticalRowSpace; + int colEnd = + std::min((col + 1) * verticalRowSpace, this->items_.size()); + + for (int i = colStart; i < colEnd; i++) + { + largestWidth = std::max( + this->items_.at(i).tab->normalTabWidth(), largestWidth); + } + + if (col == columnCount - 1 && this->showAddButton_ && + largestWidth == 0) + { + largestWidth = this->addButton_->width(); + } + + if (largestWidth + x < buttonWidth && col == columnCount - 1) + largestWidth = buttonWidth - x; + + for (int i = colStart; i < colEnd; i++) + { + auto item = this->items_.at(i); + + /// Layout tab + item.tab->growWidth(largestWidth); + item.tab->moveAnimated(QPoint(x, y), animated); + y += tabHeight; + } + + if (col == columnCount - 1 && this->showAddButton_) + { + this->addButton_->move(x, y); + } + + x += largestWidth + lineThickness; + y = top; } - - if (col == columnCount - 1 && this->showAddButton_ && - largestWidth == 0) - { - largestWidth = this->addButton_->width(); - } - - if (largestWidth + x < buttonWidth && col == columnCount - 1) - largestWidth = buttonWidth - x; - - for (int i = colStart; i < colEnd; i++) - { - auto item = this->items_.at(i); - - /// Layout tab - item.tab->growWidth(largestWidth); - item.tab->moveAnimated(QPoint(x, y), animated); - y += tabHeight; - } - - if (col == columnCount - 1 && this->showAddButton_) - { - this->addButton_->move(x, y); - } - - x += largestWidth + lineThickness; - y = top; } - x = std::max(x, buttonWidth); + x = std::max({x, buttonWidth, minimumTabAreaSpace}); if (this->lineOffset_ != x - lineThickness) { @@ -553,6 +619,20 @@ void Notebook::performLayout(bool animated) } } +void Notebook::mousePressEvent(QMouseEvent *event) +{ + this->update(); + + switch (event->button()) + { + case Qt::RightButton: { + this->menu_.popup(event->globalPos() + QPoint(0, 8)); + } + break; + default:; + } +} + void Notebook::setTabDirection(NotebookTabDirection direction) { if (direction != this->tabDirection_) @@ -713,7 +793,7 @@ SplitContainer *SplitNotebook::addPage(bool select) auto tab = Notebook::addPage(container, QString(), select); container->setTab(tab); tab->setParent(this); - tab->show(); + tab->setVisible(this->getShowTabs()); return container; } diff --git a/src/widgets/Notebook.hpp b/src/widgets/Notebook.hpp index 1169593bb..f9418e825 100644 --- a/src/widgets/Notebook.hpp +++ b/src/widgets/Notebook.hpp @@ -4,6 +4,7 @@ #include "widgets/BaseWidget.hpp" #include +#include #include #include #include @@ -49,6 +50,9 @@ public: bool getAllowUserTabManagement() const; void setAllowUserTabManagement(bool value); + bool getShowTabs() const; + void setShowTabs(bool value); + bool getShowAddButton() const; void setShowAddButton(bool value); @@ -59,6 +63,7 @@ public: protected: virtual void scaleChangedEvent(float scale_) override; virtual void resizeEvent(QResizeEvent *) override; + virtual void mousePressEvent(QMouseEvent *event) override; virtual void paintEvent(QPaintEvent *) override; NotebookButton *getAddButton(); @@ -83,12 +88,14 @@ private: NotebookTab *getTabFromPage(QWidget *page); QList items_; + QMenu menu_; QWidget *selectedPage_ = nullptr; NotebookButton *addButton_; std::vector customButtons_; bool allowUserTabManagement_ = false; + bool showTabs_ = true; bool showAddButton_ = false; int lineOffset_ = 20; NotebookTabDirection tabDirection_ = NotebookTabDirection::Horizontal; diff --git a/src/widgets/Window.cpp b/src/widgets/Window.cpp index 6913d9e88..932e05fd5 100644 --- a/src/widgets/Window.cpp +++ b/src/widgets/Window.cpp @@ -401,6 +401,10 @@ void Window::addShortcuts() new QuickSwitcherPopup(&getApp()->windows->getMainWindow()); quickSwitcher->show(); }); + + createWindowShortcut(this, "CTRL+U", [this] { + this->notebook_->setShowTabs(!this->notebook_->getShowTabs()); + }); } void Window::addMenuBar() diff --git a/src/widgets/helper/NotebookTab.cpp b/src/widgets/helper/NotebookTab.cpp index 3d0015f6c..9fdd41db0 100644 --- a/src/widgets/helper/NotebookTab.cpp +++ b/src/widgets/helper/NotebookTab.cpp @@ -73,6 +73,12 @@ NotebookTab::NotebookTab(Notebook *notebook) this->highlightEnabled_ = checked; }); this->menu_.addAction(highlightNewMessagesAction_); + + this->menu_.addSeparator(); + + this->menu_.addAction("Toggle visibility of tabs", [this]() { + this->notebook_->setShowTabs(!this->notebook_->getShowTabs()); + }); } void NotebookTab::showRenameDialog() diff --git a/src/widgets/settingspages/KeyboardSettingsPage.cpp b/src/widgets/settingspages/KeyboardSettingsPage.cpp index 0b624e090..7cad92a5f 100644 --- a/src/widgets/settingspages/KeyboardSettingsPage.cpp +++ b/src/widgets/settingspages/KeyboardSettingsPage.cpp @@ -57,6 +57,7 @@ KeyboardSettingsPage::KeyboardSettingsPage() form->addRow(new QLabel("Alt + ←/↑/→/↓"), new QLabel("Select left/upper/right/bottom split")); + form->addRow(new QLabel("Ctrl+U"), new QLabel("Toggle visibility of tabs")); form->addItem(new QSpacerItem(16, 16)); form->addRow(new QLabel("Ctrl + R"), new QLabel("Change channel"));