Qt: Add Icon Selection and Preview to the Shortcut Creator

This commit is contained in:
KamFretoZ
2026-03-19 22:06:50 +07:00
committed by lightningterror
parent 2dbae3bec9
commit 7b2fa803de
3 changed files with 182 additions and 31 deletions
+84 -25
View File
@@ -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<std::string> passed_cli_args, std::string custom_args, bool is_desktop)
void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::string game_path, std::vector<std::string> 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;
}
+1 -1
View File
@@ -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<std::string> passed_cli_args, std::string custom_args, bool is_desktop);
void CreateShortcut(const std::string name, const std::string game_path, std::vector<std::string> 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.
+97 -5
View File
@@ -10,11 +10,11 @@
<x>0</x>
<y>0</y>
<width>500</width>
<height>700</height>
<height>825</height>
</rect>
</property>
<layout class="QGridLayout" name="shortcutLayout">
<item row="4" column="0" colspan="2">
<item row="6" column="0" colspan="2">
<widget class="QGroupBox" name="launchArgsGroup">
<property name="title">
<string/>
@@ -291,7 +291,7 @@
</property>
</widget>
</item>
<item row="6" column="1">
<item row="8" column="1">
<widget class="QDialogButtonBox" name="dialogButtons">
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
@@ -301,7 +301,7 @@
</property>
</widget>
</item>
<item row="3" column="0">
<item row="5" column="0">
<widget class="QLabel" name="instruction">
<property name="text">
<string>Launch Options</string>
@@ -334,7 +334,7 @@
</layout>
</widget>
</item>
<item row="5" column="0">
<item row="7" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
@@ -347,11 +347,100 @@
</property>
</spacer>
</item>
<item row="3" column="0">
<widget class="QLabel" name="iconLabel">
<property name="text">
<string>Icon</string>
</property>
<property name="buddy">
<cstring>browseIconButton</cstring>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QGroupBox" name="iconGroup">
<property name="title">
<string/>
</property>
<layout class="QGridLayout" name="iconLayout">
<item row="1" column="2">
<widget class="QPushButton" name="resetIconButton">
<property name="toolTip">
<string>Reset to default application icon</string>
</property>
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="browseIconButton">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="0" column="0" rowspan="2">
<widget class="QLabel" name="iconPreview">
<property name="minimumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="contextMenuPolicy">
<enum>Qt::ContextMenuPolicy::NoContextMenu</enum>
</property>
<property name="frameShape">
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Raised</enum>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::NoTextInteraction</set>
</property>
<property name="buddy">
<cstring>iconPath</cstring>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="iconPath">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>Default PCSX2 Icon</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>shortcutDesktop</tabstop>
<tabstop>shortcutStartMenu</tabstop>
<tabstop>iconPath</tabstop>
<tabstop>browseIconButton</tabstop>
<tabstop>resetIconButton</tabstop>
<tabstop>portableModeToggle</tabstop>
<tabstop>overrideBootELFToggle</tabstop>
<tabstop>overrideBootELFPath</tabstop>
@@ -360,6 +449,9 @@
<tabstop>gameArgs</tabstop>
<tabstop>bootOptionToggle</tabstop>
<tabstop>bootOptionDropdown</tabstop>
<tabstop>fastForwardOptionToggle</tabstop>
<tabstop>fastForwardTurboOption</tabstop>
<tabstop>fastForwardUnlimitedOption</tabstop>
<tabstop>fullscreenMode</tabstop>
<tabstop>fullscreenModeDropdown</tabstop>
<tabstop>bigPictureModeToggle</tabstop>