From 67041d217b780c1ceedd15795d20bad11909d61a Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 1 Dec 2024 13:32:24 +1000 Subject: [PATCH] Qt: Improve shortcuts - CTRL/+, CTRL/- no longer show in menu for zooming, but still activate. - CTRL+O will open a new disc/game from file. - F5 will refresh the game list (i.e. scan for new games). - F3/CTRL+F will send focus to the game list search box. - Pressing Enter in the search box will send focus to the first game list row. - ALT+ENTER in the game list will open Game Properties. --- src/duckstation-qt/autoupdaterdialog.cpp | 10 ++++- src/duckstation-qt/gamelistwidget.cpp | 33 ++++++++++++++++- src/duckstation-qt/gamelistwidget.h | 2 + src/duckstation-qt/mainwindow.cpp | 47 +++++++++++++++++++----- src/duckstation-qt/mainwindow.h | 13 +++++++ src/duckstation-qt/mainwindow.ui | 16 -------- src/duckstation-qt/qthost.cpp | 7 +--- 7 files changed, 95 insertions(+), 33 deletions(-) diff --git a/src/duckstation-qt/autoupdaterdialog.cpp b/src/duckstation-qt/autoupdaterdialog.cpp index e5f7d8365..140742cd0 100644 --- a/src/duckstation-qt/autoupdaterdialog.cpp +++ b/src/duckstation-qt/autoupdaterdialog.cpp @@ -138,8 +138,14 @@ bool AutoUpdaterDialog::warnAboutUnofficialBuild() #if !__has_include("scmversion/tag.h") && !defined(_DEBUG) constexpr const char* CONFIG_SECTION = "UI"; constexpr const char* CONFIG_KEY = "UnofficialBuildWarningConfirmed"; - if (Host::GetBaseBoolSettingValue(CONFIG_SECTION, CONFIG_KEY, false)) + if ( +#ifndef _WIN32 + !StringUtil::StartsWithNoCase(EmuFolders::AppRoot, "/usr") && +#endif + Host::GetBaseBoolSettingValue(CONFIG_SECTION, CONFIG_KEY, false)) + { return true; + } constexpr int DELAY_SECONDS = 5; @@ -155,6 +161,8 @@ bool AutoUpdaterDialog::warnAboutUnofficialBuild() mbox.setIcon(QMessageBox::Warning); mbox.setWindowTitle(QStringLiteral("Unofficial Build Warning")); mbox.setWindowIcon(QtHost::GetAppIcon()); + mbox.setWindowFlag(Qt::CustomizeWindowHint, true); + mbox.setWindowFlag(Qt::WindowCloseButtonHint, false); mbox.setTextFormat(Qt::RichText); mbox.setText(message); diff --git a/src/duckstation-qt/gamelistwidget.cpp b/src/duckstation-qt/gamelistwidget.cpp index 0162fdaee..b912c9529 100644 --- a/src/duckstation-qt/gamelistwidget.cpp +++ b/src/duckstation-qt/gamelistwidget.cpp @@ -6,6 +6,7 @@ #include "gamelistrefreshthread.h" #include "qthost.h" #include "qtutils.h" +#include "settingswindow.h" #include "core/game_list.h" #include "core/host.h" @@ -181,6 +182,7 @@ void GameListWidget::initialize() }); connect(m_ui.searchText, &QLineEdit::textChanged, this, [this](const QString& text) { m_sort_model->setFilterName(text); }); + connect(m_ui.searchText, &QLineEdit::returnPressed, this, &GameListWidget::onSearchReturnPressed); m_table_view = new QTableView(m_ui.stack); m_table_view->setModel(m_sort_model); @@ -368,7 +370,17 @@ void GameListWidget::onTableViewItemActivated(const QModelIndex& index) if (!source_index.isValid() || source_index.row() >= static_cast(GameList::GetEntryCount())) return; - emit entryActivated(); + if (qApp->keyboardModifiers().testFlag(Qt::AltModifier)) + { + const auto lock = GameList::GetLock(); + const GameList::Entry* entry = GameList::GetEntryByIndex(static_cast(source_index.row())); + if (entry) + SettingsWindow::openGamePropertiesDialog(entry->path, entry->title, entry->serial, entry->hash, entry->region); + } + else + { + emit entryActivated(); + } } void GameListWidget::onTableViewContextMenuRequested(const QPoint& point) @@ -466,6 +478,25 @@ void GameListWidget::refreshGridCovers() m_model->refreshCovers(); } +void GameListWidget::focusSearchWidget() +{ + m_ui.searchText->setFocus(Qt::ShortcutFocusReason); +} + +void GameListWidget::onSearchReturnPressed() +{ + // Anything to switch focus to? + const int rows = m_sort_model->rowCount(); + if (rows == 0) + return; + + QAbstractItemView* const target = + isShowingGameGrid() ? static_cast(m_list_view) : static_cast(m_table_view); + target->selectionModel()->select(m_sort_model->index(0, 0), + QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + target->setFocus(Qt::ShortcutFocusReason); +} + void GameListWidget::showGameList() { if (m_ui.stack->currentIndex() == 0 || m_model->rowCount() == 0) diff --git a/src/duckstation-qt/gamelistwidget.h b/src/duckstation-qt/gamelistwidget.h index 758181e72..02ef50783 100644 --- a/src/duckstation-qt/gamelistwidget.h +++ b/src/duckstation-qt/gamelistwidget.h @@ -80,6 +80,7 @@ private Q_SLOTS: void onListViewItemActivated(const QModelIndex& index); void onListViewContextMenuRequested(const QPoint& point); void onCoverScaleChanged(); + void onSearchReturnPressed(); public Q_SLOTS: void showGameList(); @@ -91,6 +92,7 @@ public Q_SLOTS: void gridZoomOut(); void gridIntScale(int int_scale); void refreshGridCovers(); + void focusSearchWidget(); protected: void resizeEvent(QResizeEvent* event); diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp index 237cc1f3c..44e349107 100644 --- a/src/duckstation-qt/mainwindow.cpp +++ b/src/duckstation-qt/mainwindow.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -1263,6 +1264,11 @@ void MainWindow::onRemoveDiscActionTriggered() g_emu_thread->changeDisc(QString(), false, true); } +void MainWindow::onScanForNewGamesTriggered() +{ + refreshGameList(false); +} + void MainWindow::onViewToolbarActionToggled(bool checked) { Host::SetBaseBoolSettingValue("UI", "ShowToolbar", checked); @@ -1302,6 +1308,18 @@ void MainWindow::onViewSystemDisplayTriggered() switchToEmulationView(); } +void MainWindow::onViewGameGridZoomInActionTriggered() +{ + if (isShowingGameList()) + m_game_list_widget->gridZoomIn(); +} + +void MainWindow::onViewGameGridZoomOutActionTriggered() +{ + if (isShowingGameList()) + m_game_list_widget->gridZoomOut(); +} + void MainWindow::onGitHubRepositoryActionTriggered() { QtUtils::OpenURL(this, "https://github.com/stenzek/duckstation/"); @@ -1626,6 +1644,17 @@ void MainWindow::setupAdditionalUi() updateDebugMenuVisibility(); + m_shortcuts.open_file = + new QShortcut(Qt::ControlModifier | Qt::Key_O, this, this, &MainWindow::onStartFileActionTriggered); + m_shortcuts.game_list_refresh = new QShortcut(Qt::Key_F5, this, this, &MainWindow::onScanForNewGamesTriggered); + m_shortcuts.game_list_search = new QShortcut(this); + m_shortcuts.game_list_search->setKeys({Qt::ControlModifier | Qt::Key_F, Qt::Key_F3}); + connect(m_shortcuts.game_list_search, &QShortcut::activated, m_game_list_widget, &GameListWidget::focusSearchWidget); + m_shortcuts.game_grid_zoom_in = + new QShortcut(Qt::ControlModifier | Qt::Key_Plus, this, this, &MainWindow::onViewGameGridZoomInActionTriggered); + m_shortcuts.game_grid_zoom_out = + new QShortcut(Qt::ControlModifier | Qt::Key_Minus, this, this, &MainWindow::onViewGameGridZoomOutActionTriggered); + #ifdef ENABLE_RAINTEGRATION if (Achievements::IsUsingRAIntegration()) { @@ -1691,6 +1720,12 @@ void MainWindow::updateEmulationActions(bool starting, bool running, bool cheevo m_ui.actionViewGameProperties->setDisabled(starting_or_not_running); + m_shortcuts.open_file->setEnabled(!starting_or_running); + m_shortcuts.game_list_refresh->setEnabled(!starting_or_running); + m_shortcuts.game_list_search->setEnabled(!starting_or_running); + m_shortcuts.game_grid_zoom_in->setEnabled(!starting_or_running); + m_shortcuts.game_grid_zoom_out->setEnabled(!starting_or_running); + if (starting_or_running) { if (!m_ui.toolBar->actions().contains(m_ui.actionPowerOff)) @@ -1916,7 +1951,7 @@ void MainWindow::connectSignals() connect(m_ui.actionReset, &QAction::triggered, this, []() { g_emu_thread->resetSystem(true); }); connect(m_ui.actionPause, &QAction::toggled, this, [](bool active) { g_emu_thread->setSystemPaused(active); }); connect(m_ui.actionScreenshot, &QAction::triggered, g_emu_thread, &EmuThread::saveScreenshot); - connect(m_ui.actionScanForNewGames, &QAction::triggered, this, [this]() { refreshGameList(false); }); + connect(m_ui.actionScanForNewGames, &QAction::triggered, this, &MainWindow::onScanForNewGamesTriggered); connect(m_ui.actionRescanAllGames, &QAction::triggered, this, [this]() { refreshGameList(true); }); connect(m_ui.actionLoadState, &QAction::triggered, this, [this]() { m_ui.menuLoadState->exec(QCursor::pos()); }); connect(m_ui.actionSaveState, &QAction::triggered, this, [this]() { m_ui.menuSaveState->exec(QCursor::pos()); }); @@ -1968,14 +2003,8 @@ void MainWindow::connectSignals() connect(m_ui.actionMergeDiscSets, &QAction::triggered, m_game_list_widget, &GameListWidget::setMergeDiscSets); connect(m_ui.actionShowGameIcons, &QAction::triggered, m_game_list_widget, &GameListWidget::setShowGameIcons); connect(m_ui.actionGridViewShowTitles, &QAction::triggered, m_game_list_widget, &GameListWidget::setShowCoverTitles); - connect(m_ui.actionGridViewZoomIn, &QAction::triggered, m_game_list_widget, [this]() { - if (isShowingGameList()) - m_game_list_widget->gridZoomIn(); - }); - connect(m_ui.actionGridViewZoomOut, &QAction::triggered, m_game_list_widget, [this]() { - if (isShowingGameList()) - m_game_list_widget->gridZoomOut(); - }); + connect(m_ui.actionGridViewZoomIn, &QAction::triggered, this, &MainWindow::onViewGameGridZoomInActionTriggered); + connect(m_ui.actionGridViewZoomOut, &QAction::triggered, this, &MainWindow::onViewGameGridZoomOutActionTriggered); connect(m_ui.actionGridViewRefreshCovers, &QAction::triggered, m_game_list_widget, &GameListWidget::refreshGridCovers); diff --git a/src/duckstation-qt/mainwindow.h b/src/duckstation-qt/mainwindow.h index 32551795f..2d8d06faa 100644 --- a/src/duckstation-qt/mainwindow.h +++ b/src/duckstation-qt/mainwindow.h @@ -24,6 +24,7 @@ class QLabel; class QThread; class QProgressBar; +class QShortcut; class MainWindow; class GameListWidget; @@ -169,12 +170,15 @@ private Q_SLOTS: void onStartFullscreenUITriggered(); void onFullscreenUIStateChange(bool running); void onRemoveDiscActionTriggered(); + void onScanForNewGamesTriggered(); void onViewToolbarActionToggled(bool checked); void onViewLockToolbarActionToggled(bool checked); void onViewStatusBarActionToggled(bool checked); void onViewGameListActionTriggered(); void onViewGameGridActionTriggered(); void onViewSystemDisplayTriggered(); + void onViewGameGridZoomInActionTriggered(); + void onViewGameGridZoomOutActionTriggered(); void onGitHubRepositoryActionTriggered(); void onIssueTrackerActionTriggered(); void onDiscordServerActionTriggered(); @@ -296,6 +300,15 @@ private: QMenu* m_settings_toolbar_menu = nullptr; + struct + { + QShortcut* open_file = nullptr; + QShortcut* game_list_refresh = nullptr; + QShortcut* game_list_search = nullptr; + QShortcut* game_grid_zoom_in = nullptr; + QShortcut* game_grid_zoom_out = nullptr; + } m_shortcuts; + SettingsWindow* m_settings_window = nullptr; ControllerSettingsWindow* m_controller_settings_window = nullptr; diff --git a/src/duckstation-qt/mainwindow.ui b/src/duckstation-qt/mainwindow.ui index 6e97fba02..eafb2593f 100644 --- a/src/duckstation-qt/mainwindow.ui +++ b/src/duckstation-qt/mainwindow.ui @@ -836,17 +836,11 @@ Zoom &In (Grid View) - - Ctrl++ - Zoom &Out (Grid View) - - Ctrl+- - @@ -931,16 +925,6 @@ Capture GPU Frame - - - asdf - - - - - aaa - - diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp index b590eb1f1..90156681b 100644 --- a/src/duckstation-qt/qthost.cpp +++ b/src/duckstation-qt/qthost.cpp @@ -501,12 +501,7 @@ bool QtHost::SetCriticalFolders() // the resources directory should exist, bail out if not const std::string rcc_path = Path::Combine(EmuFolders::Resources, "duckstation-qt.rcc"); if (!FileSystem::FileExists(rcc_path.c_str()) || !QResource::registerResource(QString::fromStdString(rcc_path)) || -#if defined(_WIN32) || defined(__APPLE__) - !FileSystem::DirectoryExists(EmuFolders::Resources.c_str()) -#else - !FileSystem::IsRealDirectory(EmuFolders::Resources.c_str()) -#endif - ) + !FileSystem::DirectoryExists(EmuFolders::Resources.c_str())) { QMessageBox::critical(nullptr, QStringLiteral("Error"), QStringLiteral("Resources are missing, your installation is incomplete."));