diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 38d481cdf9..68529deb4c 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -314,6 +314,8 @@ add_executable(dolphin-emu QtUtils/ImageConverter.h QtUtils/ModalMessageBox.cpp QtUtils/ModalMessageBox.h + QtUtils/NonAutodismissibleMenu.cpp + QtUtils/NonAutodismissibleMenu.h QtUtils/NonDefaultQPushButton.cpp QtUtils/NonDefaultQPushButton.h QtUtils/ParallelProgressDialog.h diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index 41349a4cee..6bc6246661 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -195,6 +195,7 @@ + diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 24c6cc2d04..5fb58b8176 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -63,6 +63,7 @@ #include "DolphinQt/NANDRepairDialog.h" #include "DolphinQt/QtUtils/DolphinFileDialog.h" #include "DolphinQt/QtUtils/ModalMessageBox.h" +#include "DolphinQt/QtUtils/NonAutodismissibleMenu.h" #include "DolphinQt/QtUtils/ParallelProgressDialog.h" #include "DolphinQt/QtUtils/SetWindowDecorations.h" #include "DolphinQt/Settings.h" @@ -450,7 +451,8 @@ void MenuBar::UpdateStateSlotMenu() void MenuBar::AddViewMenu() { - QMenu* view_menu = addMenu(tr("&View")); + auto* const view_menu{new QtUtils::NonAutodismissibleMenu(tr("&View"), this)}; + addMenu(view_menu); QAction* show_log = view_menu->addAction(tr("Show &Log")); show_log->setCheckable(true); show_log->setChecked(Settings::Instance().IsLogVisible()); @@ -705,7 +707,8 @@ void MenuBar::AddListColumnsMenu(QMenu* view_menu) {tr("Tags"), &Config::MAIN_GAMELIST_COLUMN_TAGS}}; QActionGroup* column_group = new QActionGroup(this); - m_cols_menu = view_menu->addMenu(tr("List Columns")); + m_cols_menu = new QtUtils::NonAutodismissibleMenu(tr("List Columns"), view_menu); + view_menu->addMenu(m_cols_menu); column_group->setExclusive(false); for (const auto& key : columns.keys()) @@ -730,7 +733,8 @@ void MenuBar::AddShowPlatformsMenu(QMenu* view_menu) {tr("Show ELF/DOL"), &Config::MAIN_GAMELIST_LIST_ELF_DOL}}; QActionGroup* platform_group = new QActionGroup(this); - QMenu* plat_menu = view_menu->addMenu(tr("Show Platforms")); + auto* const plat_menu{new QtUtils::NonAutodismissibleMenu(tr("Show Platforms"), view_menu)}; + view_menu->addMenu(plat_menu); platform_group->setExclusive(false); for (const auto& key : platform_map.keys()) @@ -764,7 +768,8 @@ void MenuBar::AddShowRegionsMenu(QMenu* view_menu) {tr("Show World"), &Config::MAIN_GAMELIST_LIST_WORLD}, {tr("Show Unknown"), &Config::MAIN_GAMELIST_LIST_UNKNOWN}}; - QMenu* const region_menu = view_menu->addMenu(tr("Show Regions")); + auto* const region_menu{new QtUtils::NonAutodismissibleMenu(tr("Show Regions"), view_menu)}; + view_menu->addMenu(region_menu); const QAction* const show_all_regions = region_menu->addAction(tr("Show All")); const QAction* const hide_all_regions = region_menu->addAction(tr("Hide All")); region_menu->addSeparator(); @@ -792,7 +797,8 @@ void MenuBar::AddShowRegionsMenu(QMenu* view_menu) void MenuBar::AddMovieMenu() { - auto* movie_menu = addMenu(tr("&Movie")); + auto* const movie_menu{new QtUtils::NonAutodismissibleMenu(tr("&Movie"), this)}; + addMenu(movie_menu); m_recording_start = movie_menu->addAction(tr("Start Re&cording Input"), this, [this] { emit StartRecording(); }); m_recording_play = diff --git a/Source/Core/DolphinQt/QtUtils/NonAutodismissibleMenu.cpp b/Source/Core/DolphinQt/QtUtils/NonAutodismissibleMenu.cpp new file mode 100644 index 0000000000..c7aa14389d --- /dev/null +++ b/Source/Core/DolphinQt/QtUtils/NonAutodismissibleMenu.cpp @@ -0,0 +1,28 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "DolphinQt/QtUtils/NonAutodismissibleMenu.h" + +#include +#include + +namespace QtUtils +{ + +void NonAutodismissibleMenu::mouseReleaseEvent(QMouseEvent* const event) +{ + if (!event) + return; + + QAction* const action{activeAction()}; + if (action && action->isEnabled() && action->isCheckable()) + { + action->trigger(); + event->accept(); + return; + } + + QMenu::mouseReleaseEvent(event); +} + +} // namespace QtUtils diff --git a/Source/Core/DolphinQt/QtUtils/NonAutodismissibleMenu.h b/Source/Core/DolphinQt/QtUtils/NonAutodismissibleMenu.h new file mode 100644 index 0000000000..34475d6eb2 --- /dev/null +++ b/Source/Core/DolphinQt/QtUtils/NonAutodismissibleMenu.h @@ -0,0 +1,22 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +namespace QtUtils +{ + +/// A menu widget based on \c QMenu that will not be automatically dismissed when one of its +/// \em checkable actions are triggered. +class NonAutodismissibleMenu : public QMenu +{ +public: + using QMenu::QMenu; + +protected: + void mouseReleaseEvent(QMouseEvent* event) override; +}; + +} // namespace QtUtils