diff --git a/CHANGELOG.md b/CHANGELOG.md index 57e2199f3..9a5d734b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ - Major: Release plugins alpha. (#5288) - Major: Improve high-DPI support on Windows. (#4868, #5391) +- Minor: Removed the Ctrl+Shift+L hotkey for toggling the "live only" tab visibility state. (#5530) +- Minor: Moved tab visibility control to a submenu, without any toggle actions. (#5530) - Minor: Add option to customise Moderation buttons with images. (#5369) - Minor: Colored usernames now update on the fly when changing the "Color @usernames" setting. (#5300) - Minor: Added `flags.action` filter variable, allowing you to filter on `/me` messages. (#5397) @@ -38,6 +40,7 @@ - Bugfix: Fixed splits staying paused after unfocusing Chatterino in certain configurations. (#5504) - Bugfix: Links with invalid characters in the domain are no longer detected. (#5509) - Bugfix: Fixed janky selection for messages with RTL segments (selection is still wrong, but consistently wrong). (#5525) +- Bugfix: Fixed tab visibility being controllable in the emote popup. (#5530) - Dev: Update Windows build from Qt 6.5.0 to Qt 6.7.1. (#5420) - Dev: Update vcpkg build Qt from 6.5.0 to 6.7.0, boost from 1.83.0 to 1.85.0, openssl from 3.1.3 to 3.3.0. (#5422) - Dev: Unsingletonize `ISoundController`. (#5462) diff --git a/src/common/SignalVector.hpp b/src/common/SignalVector.hpp index 154bc0e72..e01ebd5aa 100644 --- a/src/common/SignalVector.hpp +++ b/src/common/SignalVector.hpp @@ -127,6 +127,27 @@ public: this->itemsChanged_(); } + bool removeFirstMatching(std::function matcher, + void *caller = nullptr) + { + assertInGuiThread(); + + for (int index = 0; index < this->items_.size(); ++index) + { + T item = this->items_[index]; + if (matcher(item)) + { + this->items_.erase(this->items_.begin() + index); + SignalVectorItemEvent args{item, index, caller}; + this->itemRemoved.invoke(args); + this->itemsChanged_(); + return true; + } + } + + return false; + } + const std::vector &raw() const { assertInGuiThread(); diff --git a/src/controllers/commands/CommandController.cpp b/src/controllers/commands/CommandController.cpp index 397e36d95..3fe398644 100644 --- a/src/controllers/commands/CommandController.cpp +++ b/src/controllers/commands/CommandController.cpp @@ -459,6 +459,8 @@ CommandController::CommandController(const Paths &paths) this->registerCommand("/debug-force-image-unload", &commands::forceImageUnload); + this->registerCommand("/debug-test", &commands::debugTest); + this->registerCommand("/shield", &commands::shieldModeOn); this->registerCommand("/shieldoff", &commands::shieldModeOff); diff --git a/src/controllers/commands/builtin/chatterino/Debugging.cpp b/src/controllers/commands/builtin/chatterino/Debugging.cpp index 1097143a3..2984aa9e9 100644 --- a/src/controllers/commands/builtin/chatterino/Debugging.cpp +++ b/src/controllers/commands/builtin/chatterino/Debugging.cpp @@ -132,4 +132,16 @@ QString forceImageUnload(const CommandContext &ctx) return ""; } +QString debugTest(const CommandContext &ctx) +{ + if (!ctx.channel) + { + return ""; + } + + ctx.channel->addSystemMessage("debug-test called"); + + return ""; +} + } // namespace chatterino::commands diff --git a/src/controllers/commands/builtin/chatterino/Debugging.hpp b/src/controllers/commands/builtin/chatterino/Debugging.hpp index 8d1857370..0cfa448ec 100644 --- a/src/controllers/commands/builtin/chatterino/Debugging.hpp +++ b/src/controllers/commands/builtin/chatterino/Debugging.hpp @@ -22,4 +22,6 @@ QString forceImageGarbageCollection(const CommandContext &ctx); QString forceImageUnload(const CommandContext &ctx); +QString debugTest(const CommandContext &ctx); + } // namespace chatterino::commands diff --git a/src/controllers/hotkeys/ActionNames.hpp b/src/controllers/hotkeys/ActionNames.hpp index 71dff1ddf..3ebd7d051 100644 --- a/src/controllers/hotkeys/ActionNames.hpp +++ b/src/controllers/hotkeys/ActionNames.hpp @@ -326,15 +326,16 @@ inline const std::map actionNames{ {"setTabVisibility", ActionDefinition{ .displayName = "Set tab visibility", - .argumentDescription = "[on, off, toggle, liveOnly, or " - "toggleLiveOnly. default: toggle]", + .argumentDescription = + "[on, off, toggle, or liveOnly. default: toggle]", .minCountArguments = 0, .maxCountArguments = 1, - .possibleArguments{{"Toggle", {}}, - {"Set to on", {"on"}}, - {"Set to off", {"off"}}, - {"Live only on", {"liveOnly"}}, - {"Live only toggle", {"toggleLiveOnly"}}}, + .possibleArguments{ + {"Toggle", {}}, + {"Show all tabs", {"on"}}, + {"Hide all tabs", {"off"}}, + {"Only show live tabs", {"liveOnly"}}, + }, .argumentsPrompt = "New value:", .argumentsPromptHover = "Should the tabs be enabled, disabled, " "toggled, or live-only.", diff --git a/src/controllers/hotkeys/Hotkey.cpp b/src/controllers/hotkeys/Hotkey.cpp index 557decd70..b6d5fc6cc 100644 --- a/src/controllers/hotkeys/Hotkey.cpp +++ b/src/controllers/hotkeys/Hotkey.cpp @@ -1,6 +1,5 @@ #include "controllers/hotkeys/Hotkey.hpp" -#include "Application.hpp" #include "common/QLogging.hpp" #include "controllers/hotkeys/ActionNames.hpp" #include "controllers/hotkeys/HotkeyController.hpp" @@ -58,7 +57,7 @@ std::vector Hotkey::arguments() const QString Hotkey::getCategory() const { - return getApp()->getHotkeys()->categoryDisplayName(this->category_); + return hotkeyCategoryDisplayName(this->category_); } Qt::ShortcutContext Hotkey::getContext() const diff --git a/src/controllers/hotkeys/HotkeyController.cpp b/src/controllers/hotkeys/HotkeyController.cpp index 4893ee620..f435bf4af 100644 --- a/src/controllers/hotkeys/HotkeyController.cpp +++ b/src/controllers/hotkeys/HotkeyController.cpp @@ -8,8 +8,54 @@ #include +namespace { + +using namespace chatterino; + +const std::map HOTKEY_CATEGORIES = { + {HotkeyCategory::PopupWindow, {"popupWindow", "Popup Windows"}}, + {HotkeyCategory::Split, {"split", "Split"}}, + {HotkeyCategory::SplitInput, {"splitInput", "Split input box"}}, + {HotkeyCategory::Window, {"window", "Window"}}, +}; + +} // namespace + namespace chatterino { +const std::map &hotkeyCategories() +{ + return HOTKEY_CATEGORIES; +} + +QString hotkeyCategoryName(HotkeyCategory category) +{ + if (!HOTKEY_CATEGORIES.contains(category)) + { + qCWarning(chatterinoHotkeys) << "Invalid HotkeyCategory passed to " + "categoryDisplayName function"; + return {}; + } + + const auto &categoryData = HOTKEY_CATEGORIES.at(category); + + return categoryData.name; +} + +QString hotkeyCategoryDisplayName(HotkeyCategory category) +{ + if (!HOTKEY_CATEGORIES.contains(category)) + { + qCWarning(chatterinoHotkeys) << "Invalid HotkeyCategory passed to " + "categoryDisplayName function"; + return {}; + } + + const auto &categoryData = HOTKEY_CATEGORIES.at(category); + + return categoryData.displayName; +} + static bool hotkeySortCompare_(const std::shared_ptr &a, const std::shared_ptr &b) { @@ -25,6 +71,9 @@ HotkeyController::HotkeyController() : hotkeys_(hotkeySortCompare_) { this->loadHotkeys(); + + this->clearRemovedDefaults(); + this->signalHolder_.managedConnect( this->hotkeys_.delayedItemsChanged, [this]() { qCDebug(chatterinoHotkeys) << "Reloading hotkeys!"; @@ -130,7 +179,7 @@ int HotkeyController::replaceHotkey(QString oldName, std::optional HotkeyController::hotkeyCategoryFromName( QString categoryName) { - for (const auto &[category, data] : this->categories()) + for (const auto &[category, data] : HOTKEY_CATEGORIES) { if (data.name == categoryName) { @@ -161,38 +210,9 @@ bool HotkeyController::isDuplicate(std::shared_ptr hotkey, return false; } -QString HotkeyController::categoryDisplayName(HotkeyCategory category) const +const std::set &HotkeyController::removedOrDeprecatedHotkeys() const { - if (this->hotkeyCategories_.count(category) == 0) - { - qCWarning(chatterinoHotkeys) << "Invalid HotkeyCategory passed to " - "categoryDisplayName function"; - return QString(); - } - - const auto &categoryData = this->hotkeyCategories_.at(category); - - return categoryData.displayName; -} - -QString HotkeyController::categoryName(HotkeyCategory category) const -{ - if (this->hotkeyCategories_.count(category) == 0) - { - qCWarning(chatterinoHotkeys) << "Invalid HotkeyCategory passed to " - "categoryName function"; - return QString(); - } - - const auto &categoryData = this->hotkeyCategories_.at(category); - - return categoryData.name; -} - -const std::map & - HotkeyController::categories() const -{ - return this->hotkeyCategories_; + return this->removedOrDeprecatedHotkeys_; } void HotkeyController::loadHotkeys() @@ -280,7 +300,7 @@ void HotkeyController::saveHotkeys() pajlada::Settings::Setting::set( section + "/keySequence", hotkey->keySequence().toString()); - auto categoryName = this->categoryName(hotkey->category()); + auto categoryName = hotkeyCategoryName(hotkey->category()); pajlada::Settings::Setting::set(section + "/category", categoryName); pajlada::Settings::Setting>::set( @@ -500,10 +520,6 @@ 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"); } } @@ -524,6 +540,17 @@ void HotkeyController::resetToDefaults() this->loadHotkeys(); } +void HotkeyController::clearRemovedDefaults() +{ + // The "toggleLiveOnly" argument was removed 2024-08-04 + this->tryRemoveDefault(HotkeyCategory::Window, QKeySequence("Ctrl+Shift+L"), + "setTabVisibility", {"toggleLiveOnly"}, + "toggle live tabs only"); + + this->warnForRemovedHotkeyActions(HotkeyCategory::Window, + "setTabVisibility", {"toggleLiveOnly"}); +} + void HotkeyController::tryAddDefault(std::set &addedHotkeys, HotkeyCategory category, QKeySequence keySequence, QString action, @@ -541,6 +568,33 @@ void HotkeyController::tryAddDefault(std::set &addedHotkeys, addedHotkeys.insert(name); } +bool HotkeyController::tryRemoveDefault(HotkeyCategory category, + QKeySequence keySequence, + QString action, + std::vector args, QString name) +{ + return this->hotkeys_.removeFirstMatching([&](const auto &hotkey) { + return hotkey->category() == category && + hotkey->keySequence() == keySequence && + hotkey->action() == action && hotkey->arguments() == args && + hotkey->name() == name; + }); +} + +void HotkeyController::warnForRemovedHotkeyActions(HotkeyCategory category, + QString action, + std::vector args) +{ + for (const auto &hotkey : this->hotkeys_) + { + if (hotkey->category() == category && hotkey->action() == action && + hotkey->arguments() == args) + { + this->removedOrDeprecatedHotkeys_.insert(hotkey->name()); + } + } +} + void HotkeyController::showHotkeyError(const std::shared_ptr &hotkey, QString warning) { diff --git a/src/controllers/hotkeys/HotkeyController.hpp b/src/controllers/hotkeys/HotkeyController.hpp index f5d5842ef..7fea8be10 100644 --- a/src/controllers/hotkeys/HotkeyController.hpp +++ b/src/controllers/hotkeys/HotkeyController.hpp @@ -17,6 +17,26 @@ class Hotkey; class HotkeyModel; +/** + * @returns a const map with the HotkeyCategory enum as its key, and HotkeyCategoryData as the value. + **/ +[[nodiscard]] const std::map & + hotkeyCategories(); + +/** + * @brief Returns the name of the given hotkey category + * + * @returns the name, or an empty string if an invalid hotkey category was given + **/ +[[nodiscard]] QString hotkeyCategoryName(HotkeyCategory category); + +/** + * @brief Returns the display name of the given hotkey category + * + * @returns the display name, or an empty string if an invalid hotkey category was given + **/ +[[nodiscard]] QString hotkeyCategoryDisplayName(HotkeyCategory category); + class HotkeyController final { public: @@ -63,28 +83,21 @@ public: [[nodiscard]] bool isDuplicate(std::shared_ptr hotkey, QString ignoreNamed); - /** - * @brief Returns the display name of the given hotkey category - * - * @returns the display name, or an empty string if an invalid hotkey category was given - **/ - [[nodiscard]] QString categoryDisplayName(HotkeyCategory category) const; - - /** - * @brief Returns the name of the given hotkey category - * - * @returns the name, or an empty string if an invalid hotkey category was given - **/ - [[nodiscard]] QString categoryName(HotkeyCategory category) const; - - /** - * @returns a const map with the HotkeyCategory enum as its key, and HotkeyCategoryData as the value. - **/ - [[nodiscard]] const std::map & - categories() const; - pajlada::Signals::NoArgSignal onItemsUpdated; + /** + * @brief Removes hotkeys that were previously added as default hotkeys. + * + * This will potentially remove hotkeys that were explicitly added by the user if they added a hotkey + * with the exact same parameters as the default hotkey. + */ + void clearRemovedDefaults(); + + /// Returns the names of removed or deprecated hotkeys the user had at launch, if any + /// + /// This is used to populate the on-launch warning in the hotkey dialog + const std::set &removedOrDeprecatedHotkeys() const; + private: /** * @brief load hotkeys from under the /hotkeys settings path @@ -118,6 +131,22 @@ private: QKeySequence keySequence, QString action, std::vector args, QString name); + /** + * @brief try to remove a default hotkey if it hasn't already been modified by the user + * + * NOTE: This could also remove a user-added hotkey assuming it matches all parameters + * + * @returns true if the hotkey was removed + **/ + bool tryRemoveDefault(HotkeyCategory category, QKeySequence keySequence, + QString action, std::vector args, + QString name); + + /// Add hotkeys matching the given arguments to list of removed/deprecated hotkeys + /// that the user should remove + void warnForRemovedHotkeyActions(HotkeyCategory category, QString action, + std::vector args); + /** * @brief show an error dialog about a hotkey in a standard format **/ @@ -137,15 +166,11 @@ private: friend class KeyboardSettingsPage; + /// Stores a list of names the user had at launch that contained deprecated or removed hotkey actions + std::set removedOrDeprecatedHotkeys_; + SignalVector> hotkeys_; pajlada::Signals::SignalHolder signalHolder_; - - const std::map hotkeyCategories_ = { - {HotkeyCategory::PopupWindow, {"popupWindow", "Popup Windows"}}, - {HotkeyCategory::Split, {"split", "Split"}}, - {HotkeyCategory::SplitInput, {"splitInput", "Split input box"}}, - {HotkeyCategory::Window, {"window", "Window"}}, - }; }; } // namespace chatterino diff --git a/src/widgets/Notebook.cpp b/src/widgets/Notebook.cpp index 0f4fa3597..db2bcac49 100644 --- a/src/widgets/Notebook.cpp +++ b/src/widgets/Notebook.cpp @@ -20,6 +20,7 @@ #include "widgets/Window.hpp" #include +#include #include #include #include @@ -54,11 +55,6 @@ Notebook::Notebook(QWidget *parent) [this](bool value) { this->setLockNotebookLayout(value); }); - this->showTabsAction_ = new QAction("Toggle visibility of tabs"); - QObject::connect(this->showTabsAction_, &QAction::triggered, [this]() { - this->setShowTabs(!this->getShowTabs()); - }); - this->updateTabVisibilityMenuAction(); this->toggleTopMostAction_ = new QAction("Top most window", this); this->toggleTopMostAction_->setCheckable(true); @@ -597,7 +593,6 @@ void Notebook::setShowTabs(bool value) this->performLayout(); this->updateTabVisibility(); - this->updateTabVisibilityMenuAction(); // show a popup upon hiding tabs if (!value && getSettings()->informOnTabVisibilityToggle.getValue()) @@ -668,35 +663,6 @@ void Notebook::updateTabVisibility() } } -void Notebook::updateTabVisibilityMenuAction() -{ - const auto *hotkeys = getApp()->getHotkeys(); - - auto toggleSeq = hotkeys->getDisplaySequence( - HotkeyCategory::Window, "setTabVisibility", {std::vector()}); - if (toggleSeq.isEmpty()) - { - toggleSeq = hotkeys->getDisplaySequence( - HotkeyCategory::Window, "setTabVisibility", {{"toggle"}}); - } - - if (toggleSeq.isEmpty()) - { - // show contextual shortcuts - if (this->getShowTabs()) - { - toggleSeq = hotkeys->getDisplaySequence( - HotkeyCategory::Window, "setTabVisibility", {{"off"}}); - } - else if (!this->getShowTabs()) - { - toggleSeq = hotkeys->getDisplaySequence( - HotkeyCategory::Window, "setTabVisibility", {{"on"}}); - } - } - this->showTabsAction_->setShortcut(toggleSeq); -} - bool Notebook::getShowAddButton() const { return this->showAddButton_; @@ -1274,8 +1240,6 @@ void Notebook::setLockNotebookLayout(bool value) void Notebook::addNotebookActionsToMenu(QMenu *menu) { - menu->addAction(this->showTabsAction_); - menu->addAction(this->lockNotebookLayoutAction_); menu->addAction(this->toggleTopMostAction_); @@ -1368,9 +1332,64 @@ SplitNotebook::SplitNotebook(Window *parent) this->addCustomButtons(); } - this->toggleOfflineTabsAction_ = new QAction({}, this); - QObject::connect(this->toggleOfflineTabsAction_, &QAction::triggered, this, - &SplitNotebook::toggleOfflineTabs); + auto *tabVisibilityActionGroup = new QActionGroup(this); + tabVisibilityActionGroup->setExclusionPolicy( + QActionGroup::ExclusionPolicy::Exclusive); + + this->showAllTabsAction = new QAction("Show all tabs", this); + this->showAllTabsAction->setCheckable(true); + this->showAllTabsAction->setShortcut( + getApp()->getHotkeys()->getDisplaySequence( + HotkeyCategory::Window, "setTabVisibility", {{"on"}})); + QObject::connect(this->showAllTabsAction, &QAction::triggered, this, + [this] { + this->setShowTabs(true); + getSettings()->tabVisibility.setValue( + NotebookTabVisibility::AllTabs); + this->showAllTabsAction->setChecked(true); + }); + tabVisibilityActionGroup->addAction(this->showAllTabsAction); + + this->onlyShowLiveTabsAction = new QAction("Only show live tabs", this); + this->onlyShowLiveTabsAction->setCheckable(true); + this->onlyShowLiveTabsAction->setShortcut( + getApp()->getHotkeys()->getDisplaySequence( + HotkeyCategory::Window, "setTabVisibility", {{"liveOnly"}})); + QObject::connect(this->onlyShowLiveTabsAction, &QAction::triggered, this, + [this] { + this->setShowTabs(true); + getSettings()->tabVisibility.setValue( + NotebookTabVisibility::LiveOnly); + this->onlyShowLiveTabsAction->setChecked(true); + }); + tabVisibilityActionGroup->addAction(this->onlyShowLiveTabsAction); + + this->hideAllTabsAction = new QAction("Hide all tabs", this); + this->hideAllTabsAction->setCheckable(true); + this->hideAllTabsAction->setShortcut( + getApp()->getHotkeys()->getDisplaySequence( + HotkeyCategory::Window, "setTabVisibility", {{"off"}})); + QObject::connect(this->hideAllTabsAction, &QAction::triggered, this, + [this] { + this->setShowTabs(false); + getSettings()->tabVisibility.setValue( + NotebookTabVisibility::AllTabs); + this->hideAllTabsAction->setChecked(true); + }); + tabVisibilityActionGroup->addAction(this->hideAllTabsAction); + + switch (getSettings()->tabVisibility.getEnum()) + { + case NotebookTabVisibility::AllTabs: { + this->showAllTabsAction->setChecked(true); + } + break; + + case NotebookTabVisibility::LiveOnly: { + this->onlyShowLiveTabsAction->setChecked(true); + } + break; + } getSettings()->tabVisibility.connect( [this](int val, auto) { @@ -1385,17 +1404,12 @@ SplitNotebook::SplitNotebook(Window *parent) this->setTabVisibilityFilter([](const NotebookTab *tab) { return tab->isLive(); }); - this->toggleOfflineTabsAction_->setText("Show all tabs"); break; case NotebookTabVisibility::AllTabs: default: this->setTabVisibilityFilter(nullptr); - this->toggleOfflineTabsAction_->setText( - "Show live tabs only"); break; } - - this->updateToggleOfflineTabsHotkey(visibility); }, this->signalHolder_, true); @@ -1448,29 +1462,26 @@ SplitNotebook::SplitNotebook(Window *parent) }); } -void SplitNotebook::toggleOfflineTabs() -{ - if (!this->getShowTabs()) - { - // Tabs are currently hidden, so the intention is to show - // tabs again before enabling the live only setting - this->setShowTabs(true); - getSettings()->tabVisibility.setValue(NotebookTabVisibility::LiveOnly); - } - else - { - getSettings()->tabVisibility.setValue( - getSettings()->tabVisibility.getEnum() == - NotebookTabVisibility::LiveOnly - ? NotebookTabVisibility::AllTabs - : NotebookTabVisibility::LiveOnly); - } -} - void SplitNotebook::addNotebookActionsToMenu(QMenu *menu) { Notebook::addNotebookActionsToMenu(menu); - menu->addAction(this->toggleOfflineTabsAction_); + + auto *submenu = menu->addMenu("Tab visibility"); + submenu->addAction(this->showAllTabsAction); + submenu->addAction(this->onlyShowLiveTabsAction); + submenu->addAction(this->hideAllTabsAction); +} + +void SplitNotebook::toggleTabVisibility() +{ + if (this->getShowTabs()) + { + this->hideAllTabsAction->trigger(); + } + else + { + this->showAllTabsAction->trigger(); + } } void SplitNotebook::showEvent(QShowEvent * /*event*/) @@ -1550,42 +1561,6 @@ void SplitNotebook::addCustomButtons() this->updateStreamerModeIcon(); } -void SplitNotebook::updateToggleOfflineTabsHotkey( - NotebookTabVisibility newTabVisibility) -{ - auto *hotkeys = getApp()->getHotkeys(); - auto getKeySequence = [&](auto argument) { - return hotkeys->getDisplaySequence(HotkeyCategory::Window, - "setTabVisibility", {{argument}}); - }; - - auto toggleSeq = getKeySequence("toggleLiveOnly"); - - switch (newTabVisibility) - { - case NotebookTabVisibility::AllTabs: - if (toggleSeq.isEmpty()) - { - toggleSeq = getKeySequence("liveOnly"); - } - break; - - case NotebookTabVisibility::LiveOnly: - if (toggleSeq.isEmpty()) - { - toggleSeq = getKeySequence("toggle"); - - if (toggleSeq.isEmpty()) - { - toggleSeq = getKeySequence("on"); - } - } - break; - } - - this->toggleOfflineTabsAction_->setShortcut(toggleSeq); -} - void SplitNotebook::updateStreamerModeIcon() { if (this->streamerModeIcon_ == nullptr) diff --git a/src/widgets/Notebook.hpp b/src/widgets/Notebook.hpp index c024998d8..e5cbd17d1 100644 --- a/src/widgets/Notebook.hpp +++ b/src/widgets/Notebook.hpp @@ -116,9 +116,6 @@ public: bool getAllowUserTabManagement() const; void setAllowUserTabManagement(bool value); - bool getShowTabs() const; - void setShowTabs(bool value); - bool getShowAddButton() const; void setShowAddButton(bool value); @@ -133,6 +130,9 @@ public: void refresh(); protected: + bool getShowTabs() const; + void setShowTabs(bool value); + void scaleChangedEvent(float scale_) override; void resizeEvent(QResizeEvent *) override; void mousePressEvent(QMouseEvent *event) override; @@ -178,7 +178,6 @@ private: * @brief Updates the visibility state of all tabs **/ void updateTabVisibility(); - void updateTabVisibilityMenuAction(); void resizeAddButton(); bool containsPage(QWidget *page); @@ -209,7 +208,6 @@ private: NotebookTabLocation tabLocation_ = NotebookTabLocation::Top; QAction *lockNotebookLayoutAction_; - QAction *showTabsAction_; QAction *toggleTopMostAction_; // This filter, if set, is used to figure out the visibility of @@ -230,7 +228,15 @@ public: void themeChangedEvent() override; void addNotebookActionsToMenu(QMenu *menu) override; - void toggleOfflineTabs(); + + /** + * Toggles between the "Show all tabs" and "Hide all tabs" tab visibility states + */ + void toggleTabVisibility(); + + QAction *showAllTabsAction; + QAction *onlyShowLiveTabsAction; + QAction *hideAllTabsAction; protected: void showEvent(QShowEvent *event) override; @@ -240,9 +246,6 @@ private: pajlada::Signals::SignalHolder signalHolder_; - QAction *toggleOfflineTabsAction_; - void updateToggleOfflineTabsHotkey(NotebookTabVisibility newTabVisibility); - // Main window on Windows has basically a duplicate of this in Window NotebookButton *streamerModeIcon_{}; void updateStreamerModeIcon(); diff --git a/src/widgets/Window.cpp b/src/widgets/Window.cpp index 4374881fd..b1c72012a 100644 --- a/src/widgets/Window.cpp +++ b/src/widgets/Window.cpp @@ -642,39 +642,33 @@ void Window::addShortcuts() if (arg == "off") { - this->notebook_->setShowTabs(false); - getSettings()->tabVisibility.setValue( - NotebookTabVisibility::AllTabs); + this->notebook_->hideAllTabsAction->trigger(); } else if (arg == "on") { - this->notebook_->setShowTabs(true); - getSettings()->tabVisibility.setValue( - NotebookTabVisibility::AllTabs); + this->notebook_->showAllTabsAction->trigger(); } else if (arg == "toggle") { - this->notebook_->setShowTabs(!this->notebook_->getShowTabs()); - getSettings()->tabVisibility.setValue( - NotebookTabVisibility::AllTabs); + this->notebook_->toggleTabVisibility(); } else if (arg == "liveOnly") { - this->notebook_->setShowTabs(true); - getSettings()->tabVisibility.setValue( - NotebookTabVisibility::LiveOnly); + this->notebook_->onlyShowLiveTabsAction->trigger(); } else if (arg == "toggleLiveOnly") { - this->notebook_->toggleOfflineTabs(); + // NOOP: Removed 2024-08-04 https://github.com/Chatterino/chatterino2/pull/5530 + return "toggleLiveOnly is no longer a valid argument for " + "setTabVisibility"; } else { qCWarning(chatterinoHotkeys) << "Invalid argument for setTabVisibility hotkey: " << arg; return QString("Invalid argument for setTabVisibility hotkey: " - "%1. Use \"on\", \"off\", \"toggle\", " - "\"liveOnly\", or \"toggleLiveOnly\".") + "%1. Use \"on\", \"off\", \"toggle\", or " + "\"liveOnly\".") .arg(arg); } diff --git a/src/widgets/dialogs/EditHotkeyDialog.cpp b/src/widgets/dialogs/EditHotkeyDialog.cpp index 0bf4a8148..3f7c61242 100644 --- a/src/widgets/dialogs/EditHotkeyDialog.cpp +++ b/src/widgets/dialogs/EditHotkeyDialog.cpp @@ -26,7 +26,7 @@ EditHotkeyDialog::EditHotkeyDialog(const std::shared_ptr hotkey, this->ui_->easyArgsPicker->setVisible(false); this->ui_->easyArgsLabel->setVisible(false); // dynamically add category names to the category picker - for (const auto &[_, hotkeyCategory] : getApp()->getHotkeys()->categories()) + for (const auto &[_, hotkeyCategory] : hotkeyCategories()) { this->ui_->categoryPicker->addItem(hotkeyCategory.displayName, hotkeyCategory.name); diff --git a/src/widgets/settingspages/KeyboardSettingsPage.cpp b/src/widgets/settingspages/KeyboardSettingsPage.cpp index 9f9ae24e5..85b899d66 100644 --- a/src/widgets/settingspages/KeyboardSettingsPage.cpp +++ b/src/widgets/settingspages/KeyboardSettingsPage.cpp @@ -91,6 +91,42 @@ KeyboardSettingsPage::KeyboardSettingsPage() } }); view->addCustomButton(resetEverything); + + // We only check this once since a user *should* not have the ability to create a new hotkey with a deprecated or removed action + // However, we also don't update this after the user has deleted a hotkey. This is a big lift that should probably be solved on the model level rather + // than individually here. Same goes for marking specific rows as deprecated/removed + const auto &removedOrDeprecatedHotkeys = + getApp()->getHotkeys()->removedOrDeprecatedHotkeys(); + + if (!removedOrDeprecatedHotkeys.empty()) + { + QString warningMessage = + "Some of your hotkeys use deprecated actions and will not " + "work as expected: "; + + bool first = true; + for (const auto &hotkeyName : removedOrDeprecatedHotkeys) + { + if (!first) + { + warningMessage.append(','); + } + warningMessage.append(' '); + warningMessage.append('"'); + warningMessage.append(hotkeyName); + warningMessage.append('"'); + + first = false; + } + warningMessage.append('.'); + auto deprecatedWarning = layout.emplace(warningMessage); + deprecatedWarning->setStyleSheet("color: yellow"); + deprecatedWarning->setWordWrap(true); + auto deprecatedWarning2 = layout.emplace( + "You can ignore this warning after you have removed or edited the " + "above-mentioned hotkeys."); + deprecatedWarning2->setStyleSheet("color: yellow"); + } } } // namespace chatterino