diff --git a/pcsx2-qt/ShortcutCreationDialog.cpp b/pcsx2-qt/ShortcutCreationDialog.cpp index a5f40396f2..4fef8d258b 100644 --- a/pcsx2-qt/ShortcutCreationDialog.cpp +++ b/pcsx2-qt/ShortcutCreationDialog.cpp @@ -41,10 +41,10 @@ ShortcutCreationDialog::ShortcutCreationDialog(QWidget* parent, const QString& t m_ui.shortcutStartMenu->setText(tr("Application Launcher")); #endif - QButtonGroup* buttonGroup = new QButtonGroup(this); - buttonGroup->setExclusive(true); - buttonGroup->addButton(m_ui.fastForwardTurboOption); - buttonGroup->addButton(m_ui.fastForwardUnlimitedOption); + QButtonGroup* speedGroup = new QButtonGroup(this); + speedGroup->setExclusive(true); + speedGroup->addButton(m_ui.fastForwardTurboOption); + speedGroup->addButton(m_ui.fastForwardUnlimitedOption); m_ui.fastForwardTurboOption->setChecked(true); connect(m_ui.overrideBootELFButton, &QPushButton::clicked, [&]() { @@ -75,6 +75,37 @@ ShortcutCreationDialog::ShortcutCreationDialog(QWidget* parent, const QString& t m_ui.loadStateIndex->setMaximum(VMManager::NUM_SAVE_STATE_SLOTS); + m_ui.iconPreview->setPixmap(QtHost::GetAppIcon().pixmap(m_ui.iconPreview->size())); + m_ui.resetIconButton->setEnabled(false); + + connect(m_ui.browseIconButton, &QPushButton::clicked, [&]() { +#if defined(_WIN32) + const QString filter = tr("Icon Files (*.ico);;All Files (*.*)"); +#else + const QString filter = tr("Image Files (*.png *.jpg *.svg *.webp);;All Files (*.*)"); +#endif + const QString icon_file = QFileDialog::getOpenFileName(this, tr("Select Icon"), QString(), filter); + if (!icon_file.isEmpty()) + { + QPixmap pixmap(icon_file); + if (pixmap.isNull()) + { + QMessageBox::critical(this, tr("Invalid Icon"), tr("The selected file could not be loaded as an icon.")); + return; + } + + m_ui.iconPath->setText(Path::ToNativePath(icon_file.toStdString()).c_str()); + m_ui.iconPreview->setPixmap(pixmap.scaled(m_ui.iconPreview->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); + m_ui.resetIconButton->setEnabled(true); + } + }); + + connect(m_ui.resetIconButton, &QPushButton::clicked, [&]() { + m_ui.iconPath->clear(); + m_ui.iconPreview->setPixmap(QtHost::GetAppIcon().pixmap(m_ui.iconPreview->size())); + m_ui.resetIconButton->setEnabled(false); + }); + if (std::getenv("container")) { m_ui.portableModeToggle->setEnabled(false); @@ -107,7 +138,7 @@ ShortcutCreationDialog::ShortcutCreationDialog(QWidget* parent, const QString& t if (m_ui.loadStateIndexToggle->isChecked()) { const s32 load_state_index = m_ui.loadStateIndex->value(); - if (load_state_index >= 1 && load_state_index <= VMManager::NUM_SAVE_STATE_SLOTS) + if (load_state_index > 0 && load_state_index <= VMManager::NUM_SAVE_STATE_SLOTS) { args.push_back("-state"); args.push_back(StringUtil::ToChars(load_state_index)); @@ -135,14 +166,15 @@ ShortcutCreationDialog::ShortcutCreationDialog(QWidget* parent, const QString& t } std::string custom_args = m_ui.customArgsInput->text().toStdString(); + std::string icon_path = m_ui.iconPath->text().toStdString(); - ShortcutCreationDialog::CreateShortcut(title.toStdString(), path.toStdString(), args, custom_args, m_ui.shortcutDesktop->isChecked()); + ShortcutCreationDialog::CreateShortcut(title.toStdString(), path.toStdString(), args, custom_args, icon_path, m_ui.shortcutDesktop->isChecked()); accept(); }); } -void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::string game_path, std::vector passed_cli_args, std::string custom_args, bool is_desktop) +void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::string game_path, std::vector passed_cli_args, std::string custom_args, const std::string icon_path, bool is_desktop) { #if defined(_WIN32) if (name.empty()) @@ -205,7 +237,7 @@ void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::s if (!lossless) { - QMessageBox::warning(this, tr("Failed to create shortcut"), tr("File path contains invalid character(s)."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok); + QMessageBox::critical(this, tr("Failed to create shortcut"), tr("File path contains invalid character(s)."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok); return; } @@ -282,8 +314,22 @@ void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::s } // Set the icon - std::string icon_path = Path::ToNativePath(Path::Combine(Path::GetDirectory(FileSystem::GetProgramPath()), "resources/icons/AppIconLarge.ico")); - const std::wstring w_icon_path = StringUtil::UTF8StringToWideString(icon_path); + std::string final_icon_path; + if (!icon_path.empty()) + { + final_icon_path = Path::ToNativePath(icon_path); + if (!FileSystem::FileExists(final_icon_path.c_str())) + { + QMessageBox::critical(this, tr("Failed to create shortcut"), tr("The selected icon file does not exist."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok); + return; + } + } + else + { + final_icon_path = Path::ToNativePath(Path::Combine(Path::GetDirectory(FileSystem::GetProgramPath()), "resources/icons/AppIconLarge.ico")); + } + + const std::wstring w_icon_path = StringUtil::UTF8StringToWideString(final_icon_path); res = pShellLink->SetIconLocation(w_icon_path.c_str(), 0); if (FAILED(res)) { @@ -365,25 +411,38 @@ void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::s return; } - // Copy PCSX2 icon - std::string icon_dest; - if (xdg_data_home) - icon_dest = fmt::format("{}/icons/hicolor/512x512/apps/", xdg_data_home); - else - icon_dest = fmt::format("{}/.local/share/icons/hicolor/512x512/apps/", home); - std::string icon_name; - if (is_flatpak) // Flatpak + if (!icon_path.empty()) { - executable_path = "flatpak run net.pcsx2.PCSX2"; - icon_name = "net.pcsx2.PCSX2"; + if (!FileSystem::FileExists(icon_path.c_str())) + { + QMessageBox::critical(this, tr("Failed to create shortcut"), tr("The selected icon file does not exist."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok); + return; + } + icon_name = icon_path; } else { - icon_name = "PCSX2"; - std::string icon_path = fmt::format("{}/{}.png", icon_dest, icon_name).c_str(); - if (FileSystem::EnsureDirectoryExists(icon_dest.c_str(), true)) - FileSystem::CopyFilePath(Path::Combine(EmuFolders::Resources, "icons/AppIconLarge.png").c_str(), icon_path.c_str(), false); + // Copy PCSX2 icon + std::string icon_dest; + if (xdg_data_home) + icon_dest = fmt::format("{}/icons/hicolor/512x512/apps/", xdg_data_home); + else + icon_dest = fmt::format("{}/.local/share/icons/hicolor/512x512/apps/", home); + + if (is_flatpak) // Flatpak + { + executable_path = "flatpak run net.pcsx2.PCSX2"; + icon_name = "net.pcsx2.PCSX2"; + } + else + { + icon_name = "PCSX2"; + std::string icon_path_dest = fmt::format("{}/{}.png", icon_dest, icon_name).c_str(); + if (FileSystem::EnsureDirectoryExists(icon_dest.c_str(), true)) + if (!FileSystem::FileExists(icon_path_dest.c_str())) + FileSystem::CopyFilePath(Path::Combine(EmuFolders::Resources, "icons/AppIconLarge.png").c_str(), icon_path_dest.c_str(), false); + } } // Shortcut CmdLine Args @@ -393,7 +452,7 @@ void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::s if (!lossless) { - QMessageBox::warning(this, tr("Failed to create shortcut"), tr("File path contains invalid character(s)."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok); + QMessageBox::critical(this, tr("Failed to create shortcut"), tr("File path contains invalid character(s)."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok); return; } diff --git a/pcsx2-qt/ShortcutCreationDialog.h b/pcsx2-qt/ShortcutCreationDialog.h index afbb29ae0a..eee8def535 100644 --- a/pcsx2-qt/ShortcutCreationDialog.h +++ b/pcsx2-qt/ShortcutCreationDialog.h @@ -15,7 +15,7 @@ public: ~ShortcutCreationDialog() = default; /// Create desktop shortcut for games - void CreateShortcut(const std::string name, const std::string game_path, std::vector passed_cli_args, std::string custom_args, bool is_desktop); + void CreateShortcut(const std::string name, const std::string game_path, std::vector passed_cli_args, std::string custom_args, const std::string icon_path, bool is_desktop); /// Escapes the given string for use with command line arguments. /// Returns a bool that indicates whether the escaping operation are lossless or not. diff --git a/pcsx2-qt/ShortcutCreationDialog.ui b/pcsx2-qt/ShortcutCreationDialog.ui index db546f40b7..6f441be6c4 100644 --- a/pcsx2-qt/ShortcutCreationDialog.ui +++ b/pcsx2-qt/ShortcutCreationDialog.ui @@ -10,11 +10,11 @@ 0 0 500 - 700 + 825 - + @@ -291,7 +291,7 @@ - + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok @@ -301,7 +301,7 @@ - + Launch Options @@ -334,7 +334,7 @@ - + Qt::Orientation::Vertical @@ -347,11 +347,100 @@ + + + + Icon + + + browseIconButton + + + + + + + + + + + + + Reset to default application icon + + + Reset + + + + + + + Browse... + + + + + + + + 64 + 64 + + + + + 64 + 64 + + + + Qt::ContextMenuPolicy::NoContextMenu + + + QFrame::Shape::StyledPanel + + + QFrame::Shadow::Raised + + + + + + false + + + Qt::AlignmentFlag::AlignCenter + + + Qt::TextInteractionFlag::NoTextInteraction + + + iconPath + + + + + + + true + + + Default PCSX2 Icon + + + + + + shortcutDesktop shortcutStartMenu + iconPath + browseIconButton + resetIconButton portableModeToggle overrideBootELFToggle overrideBootELFPath @@ -360,6 +449,9 @@ gameArgs bootOptionToggle bootOptionDropdown + fastForwardOptionToggle + fastForwardTurboOption + fastForwardUnlimitedOption fullscreenMode fullscreenModeDropdown bigPictureModeToggle