diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj
index 9309e0f66a..4be148aeab 100644
--- a/rpcs3/rpcs3.vcxproj
+++ b/rpcs3/rpcs3.vcxproj
@@ -411,6 +411,11 @@
true
true
+
+ true
+ true
+ true
+
true
true
@@ -576,6 +581,11 @@
true
true
+
+ true
+ true
+ true
+
true
true
@@ -761,6 +771,11 @@
true
true
+
+ true
+ true
+ true
+
true
true
@@ -926,6 +941,11 @@
true
true
+
+ true
+ true
+ true
+
true
true
@@ -1025,6 +1045,7 @@
+
@@ -1466,6 +1487,24 @@
.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DLLVM_AVAILABLE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE "-I$(VULKAN_SDK)\Include" "-I.\.." "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras"
+
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DBRANCH= -DLLVM_AVAILABLE -DPUGIXML_HEADER_ONLY -D_ENABLE_EXTENDED_ALIGNED_STORAGE -D_UNICODE "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras"
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -D_SCL_SECURE_NO_WARNINGS -DPUGIXML_HEADER_ONLY -D_ENABLE_EXTENDED_ALIGNED_STORAGE -D_UNICODE "-I$(VULKAN_SDK)\Include" "-I.\.." "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras"
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DPUGIXML_HEADER_ONLY -D_ENABLE_EXTENDED_ALIGNED_STORAGE -D_UNICODE "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras"
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DLLVM_AVAILABLE -D_SCL_SECURE_NO_WARNINGS -DPUGIXML_HEADER_ONLY -D_ENABLE_EXTENDED_ALIGNED_STORAGE -D_UNICODE "-I$(VULKAN_SDK)\Include" "-I.\.." "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras"
+
diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters
index 93014d3547..5d45bf67f2 100644
--- a/rpcs3/rpcs3.vcxproj.filters
+++ b/rpcs3/rpcs3.vcxproj.filters
@@ -674,6 +674,21 @@
Generated Files\Debug - LLVM
+
+ Gui\misc dialogs
+
+
+ Generated Files\Release - LLVM
+
+
+ Generated Files\Debug
+
+
+ Generated Files\Release
+
+
+ Generated Files\Debug - LLVM
+
@@ -894,6 +909,9 @@
Gui\trophy
+
+ Gui\misc dialogs
+
diff --git a/rpcs3/rpcs3qt/game_list_frame.cpp b/rpcs3/rpcs3qt/game_list_frame.cpp
index 4f372f147c..0282109f86 100644
--- a/rpcs3/rpcs3qt/game_list_frame.cpp
+++ b/rpcs3/rpcs3qt/game_list_frame.cpp
@@ -3,6 +3,7 @@
#include "settings_dialog.h"
#include "table_item_delegate.h"
#include "custom_table_widget_item.h"
+#include "input_dialog.h"
#include "Emu/Memory/vm.h"
#include "Emu/System.h"
@@ -423,6 +424,7 @@ void game_list_frame::Refresh(const bool fromDrive, const bool scrollAfter)
QString serial = qstr(game.serial);
m_notes[serial] = m_gui_settings->GetValue(gui::notes, serial, "").toString();
+ m_titles[serial] = m_gui_settings->GetValue(gui::titles, serial, "").toString().simplified();
serials.insert(serial);
auto cat = category::cat_boot.find(game.category);
@@ -469,13 +471,15 @@ void game_list_frame::Refresh(const bool fromDrive, const bool scrollAfter)
// Blame MSVC for double }}
}}
- auto op = [](const game_info& game1, const game_info& game2)
- {
- return qstr(game1->info.name).toLower() < qstr(game2->info.name).toLower();
- };
-
// Sort by name at the very least.
- std::sort(m_game_data.begin(), m_game_data.end(), op);
+ std::sort(m_game_data.begin(), m_game_data.end(), [&](const game_info& game1, const game_info& game2)
+ {
+ const QString custom_title1 = m_titles[qstr(game1->info.serial)];
+ const QString custom_title2 = m_titles[qstr(game2->info.serial)];
+ const QString title1 = custom_title1.isEmpty() ? qstr(game1->info.name) : custom_title1;
+ const QString title2 = custom_title2.isEmpty() ? qstr(game2->info.name) : custom_title2;
+ return title1.toLower() < title2.toLower();
+ });
// clean up hidden games list
m_hidden_list.intersect(serials);
@@ -618,6 +622,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
QAction* configure = myMenu.addAction(tr("&Configure"));
QAction* createPPUCache = myMenu.addAction(tr("&Create PPU Cache"));
myMenu.addSeparator();
+ QAction* renameTitle = myMenu.addAction(tr("&Rename In Game List"));
QAction* hide_serial = myMenu.addAction(tr("&Hide From Game List"));
hide_serial->setCheckable(true);
hide_serial->setChecked(m_hidden_list.contains(serial));
@@ -742,16 +747,52 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
{
m_game_compat->RequestCompatibility(true);
});
+ connect(renameTitle, &QAction::triggered, [=]
+ {
+ const QString custom_title = m_gui_settings->GetValue(gui::titles, serial, "").toString();
+ const QString old_title = custom_title.isEmpty() ? name : custom_title;
+ QString new_title;
+
+ input_dialog dlg(128, old_title, tr("Rename Title"), tr("%0\n%1\n\nYou can clear the line in order to use the original title.").arg(name).arg(serial), name, this);
+ dlg.move(globalPos);
+ connect(&dlg, &input_dialog::text_changed, this, [&new_title](const QString& text)
+ {
+ new_title = text.simplified();
+ });
+
+ if (dlg.exec() == QDialog::Accepted)
+ {
+ if (new_title.isEmpty() || new_title == name)
+ {
+ m_titles.remove(serial);
+ m_gui_settings->RemoveValue(gui::titles, serial);
+ }
+ else
+ {
+ m_titles[serial] = new_title;
+ m_gui_settings->SetValue(gui::titles, serial, new_title);
+ }
+ Refresh(true); // full refresh in order to reliably sort the list
+ }
+ });
connect(editNotes, &QAction::triggered, [=]
{
bool accepted;
const QString old_notes = m_gui_settings->GetValue(gui::notes, serial, "").toString();
- const QString new_notes = QInputDialog::getMultiLineText(this, tr("Edit Tooltip Notes"), QString("%0\n%1").arg(name).arg(serial), old_notes, &accepted);
+ const QString new_notes = QInputDialog::getMultiLineText(this, tr("Edit Tooltip Notes"), tr("%0\n%1").arg(name).arg(serial), old_notes, &accepted);
if (accepted)
{
- m_notes[serial] = new_notes;
- m_gui_settings->SetValue(gui::notes, serial, new_notes);
+ if (new_notes.simplified().isEmpty())
+ {
+ m_notes.remove(serial);
+ m_gui_settings->RemoveValue(gui::notes, serial);
+ }
+ else
+ {
+ m_notes[serial] = new_notes;
+ m_gui_settings->SetValue(gui::notes, serial, new_notes);
+ }
Refresh();
}
});
@@ -1144,8 +1185,9 @@ int game_list_frame::PopulateGameList()
if (!IsEntryVisible(game))
continue;
- const QString name = qstr(game->info.name).simplified();
const QString serial = qstr(game->info.serial);
+ const QString custom_title = m_titles[serial];
+ const QString title = custom_title.isEmpty() ? qstr(game->info.name) : custom_title;
const QString notes = m_notes[serial];
// Icon
@@ -1155,7 +1197,7 @@ int game_list_frame::PopulateGameList()
icon_item->setData(gui::game_role, QVariant::fromValue(game));
// Title
- custom_table_widget_item* title_item = new custom_table_widget_item(game->info.name);
+ custom_table_widget_item* title_item = new custom_table_widget_item(title);
if (game->hasCustomConfig)
{
title_item->setIcon(QIcon(":/Icons/custom_config.png"));
@@ -1166,7 +1208,7 @@ int game_list_frame::PopulateGameList()
if (!notes.isEmpty())
{
- const QString tool_tip = tr("%0 [%1]\n\nNotes:\n%2").arg(name).arg(serial).arg(notes);
+ const QString tool_tip = tr("%0 [%1]\n\nNotes:\n%2").arg(title).arg(serial).arg(notes);
title_item->setToolTip(tool_tip);
serial_item->setToolTip(tool_tip);
}
@@ -1245,7 +1287,7 @@ void game_list_frame::PopulateGameGrid(int maxCols, const QSize& image_size, con
// Edge cases!
if (entries == 0)
- { // For whatever reason, 0%x is division by zero. Absolute nonsense by definition of modulus. But, I'll acquiesce.
+ { // For whatever reason, 0%x is division by zero. Absolute nonsense by definition of modulus. But, I'll acquiesce.
return;
}
@@ -1256,15 +1298,14 @@ void game_list_frame::PopulateGameGrid(int maxCols, const QSize& image_size, con
m_xgrid->setRowCount(maxRows);
m_xgrid->setColumnCount(maxCols);
- QString title, serial, notes;
-
for (const auto& app : matching_apps)
{
- title = qstr(app->info.name).simplified(); // simplified() forces single line text
- serial = qstr(app->info.serial);
- notes = m_notes[serial];
+ const QString serial = qstr(app->info.serial);
+ const QString custom_title = m_titles[serial];
+ const QString title = custom_title.isEmpty() ? qstr(app->info.name) : custom_title;
+ const QString notes = m_notes[serial];
- m_xgrid->addItem(app->pxmap, title, r, c);
+ m_xgrid->addItem(app->pxmap, title, r, c);
m_xgrid->item(r, c)->setData(gui::game_role, QVariant::fromValue(app));
if (!notes.isEmpty())
diff --git a/rpcs3/rpcs3qt/game_list_frame.h b/rpcs3/rpcs3qt/game_list_frame.h
index c355a40582..7377a99ddd 100644
--- a/rpcs3/rpcs3qt/game_list_frame.h
+++ b/rpcs3/rpcs3qt/game_list_frame.h
@@ -262,6 +262,7 @@ private:
Qt::SortOrder m_colSortOrder;
int m_sortColumn;
QMap m_notes;
+ QMap m_titles;
// Categories
QStringList m_categoryFilters;
diff --git a/rpcs3/rpcs3qt/gui_settings.cpp b/rpcs3/rpcs3qt/gui_settings.cpp
index f7f7c9577c..b46bc99000 100644
--- a/rpcs3/rpcs3qt/gui_settings.cpp
+++ b/rpcs3/rpcs3qt/gui_settings.cpp
@@ -109,6 +109,13 @@ void gui_settings::Reset(bool removeMeta)
}
}
+void gui_settings::RemoveValue(const QString& key, const QString& name)
+{
+ m_settings.beginGroup(key);
+ m_settings.remove(name);
+ m_settings.endGroup();
+}
+
QVariant gui_settings::GetValue(const gui_save& entry)
{
return m_settings.value(entry.key + "/" + entry.name, entry.def);
diff --git a/rpcs3/rpcs3qt/gui_settings.h b/rpcs3/rpcs3qt/gui_settings.h
index 579815b315..50f20efe50 100644
--- a/rpcs3/rpcs3qt/gui_settings.h
+++ b/rpcs3/rpcs3qt/gui_settings.h
@@ -129,6 +129,7 @@ namespace gui
const QString savedata = "SaveData";
const QString users = "Users";
const QString notes = "Notes";
+ const QString titles = "Titles";
const QColor gl_icon_color = QColor(36, 36, 36, 255);
@@ -262,6 +263,9 @@ public:
public Q_SLOTS:
void Reset(bool removeMeta = false);
+ /** Remove entry */
+ void RemoveValue(const QString& key, const QString& name);
+
/** Write value to entry */
void SetValue(const gui_save& entry, const QVariant& value);
void SetValue(const QString& key, const QString& name, const QVariant& value);
diff --git a/rpcs3/rpcs3qt/input_dialog.cpp b/rpcs3/rpcs3qt/input_dialog.cpp
new file mode 100644
index 0000000000..edd590d5cd
--- /dev/null
+++ b/rpcs3/rpcs3qt/input_dialog.cpp
@@ -0,0 +1,33 @@
+#include "input_dialog.h"
+
+#include
+#include
+
+input_dialog::input_dialog(int max_length, const QString& text, const QString& title, const QString& label, const QString& placeholder, QWidget *parent, Qt::WindowFlags f)
+ : QDialog(parent, f)
+{
+ setWindowTitle(title);
+
+ QLabel* m_label = new QLabel(label);
+
+ QLineEdit* m_input = new QLineEdit();
+ m_input->setPlaceholderText(placeholder);
+ m_input->setText(text);
+ m_input->setMaxLength(max_length);
+ m_input->setClearButtonEnabled(true);
+ connect(m_input, &QLineEdit::textChanged, this, &input_dialog::text_changed);
+
+ QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ connect(button_box, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
+
+ QVBoxLayout* layout = new QVBoxLayout();
+ layout->addWidget(m_label);
+ layout->addWidget(m_input);
+ layout->addWidget(button_box);
+ setLayout(layout);
+
+ setFixedHeight(sizeHint().height());
+}
+
+input_dialog::~input_dialog(){}
diff --git a/rpcs3/rpcs3qt/input_dialog.h b/rpcs3/rpcs3qt/input_dialog.h
new file mode 100644
index 0000000000..922d1e9def
--- /dev/null
+++ b/rpcs3/rpcs3qt/input_dialog.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+class input_dialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ input_dialog(int max_length, const QString& text, const QString& title, const QString& label, const QString& placeholder, QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
+ ~input_dialog();
+
+private:
+ QString m_text;
+
+Q_SIGNALS:
+ void text_changed(const QString& text);
+};