diff --git a/src/duckstation-qt/gamelistmodel.cpp b/src/duckstation-qt/gamelistmodel.cpp
index 1e77277dc..c3e422bb8 100644
--- a/src/duckstation-qt/gamelistmodel.cpp
+++ b/src/duckstation-qt/gamelistmodel.cpp
@@ -124,6 +124,8 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const
{
case GameListEntryType::Disc:
return m_type_disc_pixmap;
+ case GameListEntryType::Playlist:
+ return m_type_playlist_pixmap;
case GameListEntryType::PSExe:
default:
return m_type_exe_pixmap;
@@ -275,6 +277,7 @@ void GameListModel::loadCommonImages()
// TODO: Use svg instead of png
m_type_disc_pixmap.load(QStringLiteral(":/icons/media-optical-24.png"));
m_type_exe_pixmap.load(QStringLiteral(":/icons/applications-system-24.png"));
+ m_type_playlist_pixmap.load(QStringLiteral(":/icons/address-book-new-22.png"));
m_region_eu_pixmap.load(QStringLiteral(":/icons/flag-eu.png"));
m_region_jp_pixmap.load(QStringLiteral(":/icons/flag-jp.png"));
m_region_us_pixmap.load(QStringLiteral(":/icons/flag-us.png"));
diff --git a/src/duckstation-qt/gamelistmodel.h b/src/duckstation-qt/gamelistmodel.h
index 8cb6e5b5d..547555951 100644
--- a/src/duckstation-qt/gamelistmodel.h
+++ b/src/duckstation-qt/gamelistmodel.h
@@ -53,6 +53,7 @@ private:
QPixmap m_type_disc_pixmap;
QPixmap m_type_exe_pixmap;
+ QPixmap m_type_playlist_pixmap;
QPixmap m_region_jp_pixmap;
QPixmap m_region_eu_pixmap;
diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp
index 3bf5c69d7..bc28a4fb3 100644
--- a/src/duckstation-qt/mainwindow.cpp
+++ b/src/duckstation-qt/mainwindow.cpp
@@ -29,7 +29,8 @@
static constexpr char DISC_IMAGE_FILTER[] =
"All File Types (*.bin *.img *.cue *.chd *.exe *.psexe *.psf);;Single-Track Raw Images (*.bin *.img);;Cue Sheets "
- "(*.cue);;MAME CHD Images (*.chd);;PlayStation Executables (*.exe *.psexe);;Portable Sound Format Files (*.psf)";
+ "(*.cue);;MAME CHD Images (*.chd);;PlayStation Executables (*.exe *.psexe);;Portable Sound Format Files "
+ "(*.psf);;Playlists (*.m3u)";
ALWAYS_INLINE static QString getWindowTitle()
{
@@ -294,6 +295,16 @@ void MainWindow::onChangeDiscFromGameListActionTriggered()
switchToGameListView();
}
+void MainWindow::onChangeDiscFromPlaylistMenuAboutToShow()
+{
+ m_host_interface->populatePlaylistEntryMenu(m_ui.menuChangeDiscFromPlaylist);
+}
+
+void MainWindow::onChangeDiscFromPlaylistMenuAboutToHide()
+{
+ m_ui.menuChangeDiscFromPlaylist->clear();
+}
+
void MainWindow::onRemoveDiscActionTriggered()
{
m_host_interface->changeDisc(QString());
@@ -567,6 +578,10 @@ void MainWindow::connectSignals()
connect(m_ui.actionChangeDiscFromFile, &QAction::triggered, this, &MainWindow::onChangeDiscFromFileActionTriggered);
connect(m_ui.actionChangeDiscFromGameList, &QAction::triggered, this,
&MainWindow::onChangeDiscFromGameListActionTriggered);
+ connect(m_ui.menuChangeDiscFromPlaylist, &QMenu::aboutToShow, this,
+ &MainWindow::onChangeDiscFromPlaylistMenuAboutToShow);
+ connect(m_ui.menuChangeDiscFromPlaylist, &QMenu::aboutToHide, this,
+ &MainWindow::onChangeDiscFromPlaylistMenuAboutToHide);
connect(m_ui.actionRemoveDisc, &QAction::triggered, this, &MainWindow::onRemoveDiscActionTriggered);
connect(m_ui.actionAddGameDirectory, &QAction::triggered,
[this]() { getSettingsDialog()->getGameListSettingsWidget()->addSearchDirectory(this); });
diff --git a/src/duckstation-qt/mainwindow.h b/src/duckstation-qt/mainwindow.h
index 1facc3fa8..0e1d0c2d7 100644
--- a/src/duckstation-qt/mainwindow.h
+++ b/src/duckstation-qt/mainwindow.h
@@ -55,6 +55,8 @@ private Q_SLOTS:
void onStartBIOSActionTriggered();
void onChangeDiscFromFileActionTriggered();
void onChangeDiscFromGameListActionTriggered();
+ void onChangeDiscFromPlaylistMenuAboutToShow();
+ void onChangeDiscFromPlaylistMenuAboutToHide();
void onRemoveDiscActionTriggered();
void onGitHubRepositoryActionTriggered();
void onIssueTrackerActionTriggered();
diff --git a/src/duckstation-qt/mainwindow.ui b/src/duckstation-qt/mainwindow.ui
index a8d927a7d..458d04621 100644
--- a/src/duckstation-qt/mainwindow.ui
+++ b/src/duckstation-qt/mainwindow.ui
@@ -45,8 +45,14 @@
:/icons/media-optical.png:/icons/media-optical.png
+
+